【问题标题】:Why does the Go image package cut+paste looping over pixels?为什么 Go 图像包剪切+粘贴会在像素上循环?
【发布时间】:2011-10-02 11:39:46
【问题描述】:

如果您查看http://golang.org/src/pkg/image/image.go 此处的图像包,您会发现每个图像的 Opaque() 实现都做同样的事情,只是像素特定的逻辑不同。

这是有原因的吗?任何通用解决方案的效率都会降低吗?这只是一个疏忽吗?类型系统是否有一些限制(我看不到)会使多态 [was: 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)的方式。

【问题讨论】:

    标签: coding-style types go standard-library


    【解决方案1】:

    类型系统有一个限制,它阻止了通用解决方案(或至少使它非常低效)。

    例如,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 中还没有泛型的解决方案。

    【讨论】:

    • 你不能写一个函数来接受第二个函数,包括检查像素的逻辑吗?
    • 我已经用我正在考虑的解决方案扩展了我的问题 - 它不是编译,但这可能是一个单独的问题。
    • (也许我误解了您的回复,但我认为您的问题在于以通用方式处理数组;我的建议更像是折叠,使用接口多态)。跨度>
    • 啊,是的,那行得通。它的效率会降低,但如果没有基准测试,很难说多少。您唯一需要更改代码的就是使 AllPixels 的第一个参数不是指针。你几乎不想在 Go 中使用指向接口的指针。它们是轻量级的,可以按值传递。
    • 感谢您的回复 - 知道我并没有完全迷失这一点真的很有用!有一个正确的答案;o)虽然我猜答案确实是“可能是效率”。
    【解决方案2】:

    Why does Go not have generic types?

    可能会在某些地方添加泛型 观点。我们没有紧迫感 他们,虽然我们了解一些 程序员做的。

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

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

    【讨论】:

    • 我不应该使用“通用”这个词。 go 确实通过鸭子类型具有某种多态性。这还不够吗?请参阅我上面添加的示例。
    猜你喜欢
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-06
    相关资源
    最近更新 更多