为什么Go图像包在像素上剪切+粘贴循环?

时间:2011-07-11 02:56:12

标签: coding-style types go standard-library

如果你看一下这里的图像包http://golang.org/src/pkg/image/image.go,你会发现每个图像的Opaque()实现都是一样的,只是在像素特定的逻辑上不同。

这有什么理由吗?任何一般解决方案效率会降低吗?这只是一个疏忽吗?是否有一些限制(我看不到一个)类型系统会使多态[is:generic]方法变得困难?

[edit]我想到的那种解决方案(在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来说还是很新的 - 它会用图像编译,但不能用图像指针编译!)。

难以优化吗? (您需要具有函数内联,但是不会将任何类型检查从循环中拉出来吗?)。此外,我现在意识到我之前不应该使用“通用”这个词 - 我只是以通用(ha)的方式使用它。

2 个答案:

答案 0 :(得分: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的每个单独的元素,并传递它,但这将是非常低效的。

观察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中还没有针对仿制药的解决方案。

答案 1 :(得分:1)

  

Why does Go not have generic types?

     

一些人可能会添加泛型   点。我们感到不紧急   他们,虽然我们了解一些   程序员做的。

     

泛型很方便,但它们来了   代价是复杂的类型   系统和运行时。我们还没有   找到了一种赋予价值的设计   与复杂性成比例,   虽然我们继续思考   它。同时,Go的内置地图和   切片,加上使用的能力   要构造的空接口   容器(带有显式拆箱)   在许多情况下意味着有可能   编写做泛型的代码   如果不太顺利,将会启用。

     

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