为什么Go图像包要循环遍历像素进行剪切和粘贴操作?

huangapple go评论91阅读模式
英文:

Why does the Go image package cut+paste looping over pixels?

问题

如果你查看这里的图像包http://golang.org/src/pkg/image/image.go,你会发现每个图像的Opaque()实现都做着相同的事情,只是在像素特定逻辑上有所不同。

这是有原因的吗?任何通用解决方案是否效率更低?这只是一个疏忽吗?是否有一些限制(我看不到)使得多态方法(曾经是:泛型)的方法变得困难?

[编辑]我想到的解决方案(不需要Java中的泛型)可能是这样的:

type ColorPredicate func(c image.Color) bool;

func AllPixels(p *image.Image, q ColorPredicate) bool {
  var r = p.Bounds()
  if r.Empty() {
    return true
  }
  for y := r.Min.Y; y < r.Max.Y; y++ {
    for x := r.Min.X; x < r.Max.X; x++ {
      if !q(p.At(x, y)) {
        return false
      }
    }
  }
  return true
}

但是我在编译时遇到了一些问题(对Go还非常陌生 - 它可以编译图像,但不能编译图像指针!)。

这是否太难优化了?(你需要进行函数内联,但是任何类型检查都会被提出循环吗?)另外,我现在意识到我之前不应该使用“泛型”这个词 - 我只是以一种通用的方式使用它。

英文:

If you look at the image package here http://golang.org/src/pkg/image/image.go you can see that the implementation of Opaque() for every image does the same thing, differing only in the pixel-specific logic.

Is there a reason for this? Would any general solution be less efficient? Is it just an oversight? Is there some limitation (I cannot see one) to the type system that would make a polymorphic [was: generic] approach difficult?

[edit] The kind of solution I was thinking of (which does not need generics in the Java sense) would be like:

<pre><code>
type ColorPredicate func(c image.Color) bool;

func AllPixels (p *image.Image, q ColorPredicate) bool {
var r = p.Bounds()
if r.Empty() {
return true
}
for y := r.Min.Y; y &lt; r.Max.Y; y++ {
for x := r.Min.X; x &lt; r.Max.X; x++ {
if ! q(p.At(x,y)) {
return false
}
}
}
return true
}
</code></pre>

but I am having trouble getting that to compile (still very new to Go - it will compile with an image, but not with an image pointer!).

Is that too hard to optimise? (you would need to have function inlining, but then wouldn't any type checking be pulled out of the loop?). Also, I now realise I shouldn't have used the word "generic" earlier - I meant it only in a generic (ha) way.

答案1

得分: 4

类型系统存在一种限制,阻止了一种通用解决方案(或者至少使其非常低效)。

例如,RGBA.Opaque和NRGBA.Opaque的实现是相同的,因此你可能认为它们可以被提取到一个第三个函数中,其签名类似于:

func opaque(pix []Color, stride int, rect Rectangle) bool

你希望以这种方式调用该函数:

func (p *RGBA) Opaque() bool {
    return opaque([]Color(p.Pix), p.Stride, p.Rect)
}

但是你不能这样做。p.Pix无法转换为[]Color,因为这些类型在内存中的表示方式不同,规范禁止这样做。我们可以分配一个新的切片,将p.Pix的每个元素转换为[]Color的元素,并传递该切片,但这样做效率非常低。

注意RGBAColor和NRGBAColor具有完全相同的结构。也许我们可以将函数提取出来,只针对这两种类型,因为像素切片的内存表示完全相同:

func opaque(pix []RGBAColor, stride int, rect Rectangle) bool

func (p *NRGBA) Opaque() bool {
    return opaque([]RGBAColor(p.Pix), p.Stride, p.Rect)
}

然而,很遗憾,这也是不允许的。这似乎更多是一个规范/语言问题,而不是技术问题。我确信这在邮件列表上已经讨论过,但我找不到一个好的讨论。

这似乎是泛型会派上用场的一个领域,但目前Go语言还没有泛型的解决方案。

英文:

There is a limitation to the type system which prevents a general solution (or at least makes it very inefficient).

For example, the bodies of RGBA.Opaque and NRGBA.Opaque are identical, so you'd think that they could be factored out into a third function with a signature something like this:

func opaque(pix []Color, stride int, rect Rectangle) bool

You'd like to call that function this way:

func (p *RGBA) Opaque() bool {
    return opaque([]Color(p.Pix), p.Stride, p.Rect)
}

But you can't. p.Pix can't be converted to []Color because those types have different in-memory representations and the spec forbids it. We could allocate a new slice, convert each individual element of p.Pix, and pass that, but that would be very inefficient.

Observe that RGBAColor and NRGBAColor have the exact same structure. Maybe we could factor out the function for just those two types, since the in-memory representation of the pixel slices is exactly the same:

func opaque(pix []RGBAColor, stride int, rect Rectangle) bool

func (p *NRGBA) Opaque() bool {
    return opaque([]RGBAColor(p.Pix), p.Stride, p.Rect)
}

Alas, again this isn't allowed. This seems to be more of a spec/language issue than a technical one. I'm sure this has come up on the mailing list before, but I can't find a good discussion of it.

This seems like an area where generics would come in handy, but there's no solution for generics in Go yet.

答案2

得分: 1

为什么Go语言没有泛型类型?

泛型可能会在某个时候被添加进来。我们并不感到迫切需要它们,尽管我们理解一些程序员的需求。

泛型很方便,但是它们会增加类型系统和运行时的复杂性。我们还没有找到一个设计,能够在复杂性上提供相应的价值,尽管我们一直在思考这个问题。与此同时,Go语言内置的映射和切片,再加上使用空接口构建容器(需要显式拆箱),意味着在许多情况下,可以编写能够实现泛型功能的代码,尽管不够灵活。

这仍然是一个未解决的问题。

英文:

> Why does Go not have generic
> types?

>
> Generics may well be added at some
> point. We don't feel an urgency for
> them, although we understand some
> programmers do.
>
> Generics are convenient but they come
> at a cost in complexity in the type
> system and run-time. We haven't yet
> found a design that gives value
> proportionate to the complexity,
> although we continue to think about
> it. Meanwhile, Go's built-in maps and
> slices, plus the ability to use the
> empty interface to construct
> containers (with explicit unboxing)
> mean in many cases it is possible to
> write code that does what generics
> would enable, if less smoothly.
>
> This remains an open issue.

huangapple
  • 本文由 发表于 2011年7月11日 10:56:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/6645329.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定