Go错误: “嵌入类型不能是指向接口的指针”

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

Go error: "embedded type cannot be a pointer to interface"

问题

以下代码会在编译时出现错误:

type IFile interface {
    Read() (n int, err error)
    Write() (n int, err error)
}

type TestFile struct {
   *IFile
}

错误信息:

./test.go:18: 嵌入类型不能是接口的指针

为什么不能嵌入 *IFile

英文:

The following code gives compile-time error:

type IFile interface {
    Read() (n int, err error)
    Write() (n int, err error)
}

type TestFile struct {
   *IFile
}

Error:

> ./test.go:18: embedded type cannot be a pointer to interface

Why can't I embed *IFile?

答案1

得分: 4

语言规范不允许这样做。规范中相关的部分是:结构类型:

声明了类型但没有显式字段名的字段是_匿名_字段,也称为_嵌入_字段或将类型嵌入结构中。嵌入类型必须指定为类型名T非接口指针类型名*T,而T本身不能是指针类型。未限定的类型名充当字段名。

指向接口类型的指针很少有用,因为接口类型可以保存指针或非指针值。

话虽如此,如果实现了你的IFile类型的具体类型是指针类型,那么指针值将被包装在类型为IFile的接口值中,所以你仍然需要嵌入IFile,只是实现IFile的值将是指针值,例如:

// 假设*FileImpl实现了IFile:
f := TestFile{IFile: &FileImpl{}}

**编辑:**回答你的评论:

首先,这是Go语言,不是C++。在Go语言中,接口不是指针,而是表示为(type;value)的一对值,其中"value"可以是指针或非指针。更多信息请参阅博文:反射定律:接口的表示方式

其次,如果FileImpl是一个类型,f := TestFile{IFile : &FileIml}显然是一个编译时错误,你需要一个*FileImpl的值,而&FileImpl显然不是。你需要使用复合字面量,形式为&FileImpl{},所以应该按照我上面发布的方式。

英文:

The language spec does not allow it. Relevant section from the spec: Struct types:

> A field declared with a type but no explicit field name is an anonymous field, also called an embedded field or an embedding of the type in the struct. An embedded type must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.

A pointer to an interface type is very rarely useful, as an interface type may hold a pointer or a non-pointer value.

Having said that, if a concrete type that implements your IFile type is a pointer type, then a pointer value will be wrapped in an interface value of type IFile, so you still have to embed IFile, just the value that implements IFile will be a pointer value, e.g.

// Let's say *FileImpl implements IFile:
f := TestFile{IFile: &FileImpl{}}

Edit: Answer to your comment:

First, this is Go, not C++. In Go, interfaces are not pointers, but they are represented as a pair of (type;value), where "value" may be pointer or non-pointer. More about this in blog post: The Laws of Reflection: The representation of an interface.

Second, if FileImpl is a type, f := TestFile{IFile : &FileIml} is obviously a compile-time error, you need a value of *FileImpl and &FileImpl clearly isn't. You need for example a composite literal which is in the form of &FileImpl{}, so it should be as I posted above.

huangapple
  • 本文由 发表于 2016年11月9日 16:47:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/40502863.html
匿名

发表评论

匿名网友

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

确定