Go:回调函数返回接口的实现

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

Go: function callback returning implementation of interface

问题

我有一个处理资源解析的系统(将名称匹配到文件路径等)。它解析文件列表,然后保留指向返回接口实现实例的函数的指针。

更容易通过示例来说明。

resource.go

package resource

var (
    tex_types    map[string]func(string) *Texture = make(map[string]func(string) *Texture)
    shader_types map[string]func(string) *Shader  = make(map[string]func(string) *Shader)
)

type Texture interface {
    Texture() (uint32, error)
    Width() int
    Height() int
}

func AddTextureLoader(ext string, fn func(string) *Texture) {
    tex_types[ext] = fn
}

dds.go

package texture

type DDSTexture struct {
    path   string
    _tid   uint32
    height uint32
    width  uint32
}

func NewDDSTexture(filename string) *DDSTexture {
    return &DDSTexture{
        path:   filename,
        _tid:   0,
        height: 0,
        width:  0,
    }
}

func init() {
    resource.AddTextureLoader("dds", NewDDSTexture)
}

DDSTexture 完全实现了 Texture 接口,我只是省略了那些函数,因为它们很大并且不是我问题的一部分。

在编译这两个包时,出现以下错误:

resource\texture\dds.go:165: cannot use NewDDSTexture (type func(string) *DDSTexture) as type func (string) *resource.Texture in argument to resource.AddTextureLoader

我该如何解决这个问题,或者这是接口系统的一个错误吗?再次强调:DDSTexture 完全实现了 resource.Texture

英文:

I got a system that handles the resolving of resources (matching a name to a file path, etc). It parses a list of files and then keeps pointers to a function that returns an instance of an implementation of an interface.

It's easier to show.

resource.go

package resource

var (
    tex_types    map[string]func(string) *Texture = make(map[string]func(string) *Texture)
    shader_types map[string]func(string) *Shader  = make(map[string]func(string) *Shader)
)

type Texture interface {
    Texture() (uint32, error)
    Width() int
    Height() int
}

func AddTextureLoader(ext string, fn func(string) *Texture) {
    tex_types[ext] = fn
}

dds.go

package texture

type DDSTexture struct {
	path   string
	_tid   uint32
	height uint32
	width  uint32
}

func NewDDSTexture(filename string) *DDSTexture {
	return &DDSTexture{
		path:   filename,
		_tid:   0,
		height: 0,
		width:  0,
	}
}


func init() {
	resource.AddTextureLoader("dds", NewDDSTexture)
}

DDSTexture fully implements the Texture interface, I just omitted those functions because they're huge and not part of my question.

When compiling these two packages, the following error arises:

resource\texture\dds.go:165: cannot use NewDDSTexture (type func(string) *DDSTexture) as type func (string) *resource.Texture in argument to resource.AddTextureLoader

How would I resolve this problem, or is this a bug with the interface system? Just reiterating: DDSTexture fully implements resource.Texture.

答案1

得分: 5

是的,DDSTexture完全实现了resource.Texture

但是,命名类型NewDDSTexture(type func(string)*DDSTexture)与无名类型func(string)*resource.Texture不同:它们的**类型标识**不匹配:

> 如果两个函数类型具有相同数量的参数和结果值,相应的参数和结果类型相同,并且两个函数都是可变参数或都不是,则它们是相同的。参数和结果名称不需要匹配。
>
> 命名类型和无名类型始终不同。

即使为函数定义了命名类型,也无法工作:

type FuncTexture func(string) *Texture
func AddTextureLoader(ext string, fn FuncTexture)

无法将NewDDSTexture(类型为func(string)`*DDSTexture`)作为参数传递给AddTextureLoader中的类型`FuncTexture`

在这里,结果值类型不匹配DDSTextureresource.Texture
即使一个实现了另一个的接口,它们的底层类型仍然不同):你不能将一个赋值给另一个。

你需要让NewDDSTexture()返回Texture(不是指针,因为它是一个接口)。

func NewDDSTexture(filename string) Texture

参见这个示例

正如我在“在golang中将结构指针转换为接口指针”中解释的那样,通常不需要指向接口的指针。

英文:

Yes, DDSTexture fully implements resource.Texture.

But the named type NewDDSTexture (type func(string) *DDSTexture) isn't the same as the unamed type func (string) *resource.Texture: their type identity doesn't match:

> Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.
>
> A named and an unnamed type are always different.

Even if you defined a named type for your function, it wouldn't work:

type FuncTexture func(string) *Texture
func AddTextureLoader(ext string, fn FuncTexture)

cannot use NewDDSTexture (type func(string) `*DDSTexture`) 
as type `FuncTexture` in argument to `AddTextureLoader`

Here, the result value type don't match DDSTexture vs. resource.Texture:
Even if one implements the interface of the other, their underlying type still differ): you cannot assign one to the other.

You need for NewDDSTexture() to return Texture (no pointer, since it is an interface).

func NewDDSTexture(filename string) Texture

See this example.

As I explained in "Cast a struct pointer to interface pointer in golang", you usually don't need a pointer to an interface.

huangapple
  • 本文由 发表于 2014年12月8日 15:18:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/27353148.html
匿名

发表评论

匿名网友

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

确定