问题描述
已经有几个Q& As在这个没有实现Y(...方法有一个指针接收器)的事情,但对我来说,他们似乎在谈论不同的事情,而不适用于我的具体情况。
因此,我没有把问题做得非常具体,而是把它放宽和抽象 - 似乎有几种不同的可以让这个错误发生的案例,请问有人可以总结一下吗?
即,如何避免这个问题,如果发生了,有什么可能? Thx。
当您尝试分配或传递(或转换) / em>键入一个接口类型;而类型本身并没有实现这个接口,只有一个指向类型的指针。
让我们来看一个例子:
/ code>),如果我们使用一个指针 * MyType2 ,它将一直工作(在):
type MyType2 struct {
* MyType
}
m:= MyType {value:something}
m2:= MyType2 {MyType:& m}
var s Stringer
s =& m2
一个href =https://golang.org/ref/spec#Struct_types =noreferrer>结构类型):
换句话说:如果我们嵌入一个non-指针类型,非指针嵌入器的方法集只获取非指针接收器的方法(来自嵌入类型)。
如果我们嵌入指针类型,非指针嵌入器的方法集获得了指针和非指针接收器(来自嵌入类型)的方法。
如果我们使用指向嵌入器的指针值,无论嵌入类型是否为指针,指向嵌入器的指针的方法集总是获取指针和非指针接收器(来自嵌入类型)的方法。
注意:
有一个非常相似的情况,即当您有一个包含值 MyType 的接口值时,您尝试其他接口值, Stringer 。在这种情况下,由于上述原因,断言不会成立,但我们得到的运行时错误稍有不同:
m: = MyType {value:something}
var i interface {} = m
fmt.Println(i。(Stringer))
运行时恐慌(请在):
panic:界面转换:main.MyType不是main.Stringer:
缺少方法String
试图转换而不是类型assert,我们得到了编译时错误关于:
m:= MyType {value:something}
fmt.Println(Stringer (m))
There are already several Q&As on this "X does not implement Y (... method has a pointer receiver)" thing, but to me, they seems to be talking about different things, and not applying to my specific case.
So, instead of making the question very specific, I'm making it broad and abstract -- Seems like there are several different cases that can make this error happen, can someone summary it up please?
I.e., how to avoid the problem, and if it occurs, what are the possibilities? Thx.
解决方案This compile-time error arises when you try to assign or pass (or convert) a concrete type to an interface type; and the type itself does not implement the interface, only a pointer to the type.
Let's see an example:
type Stringer interface { String() string } type MyType struct { value string } func (m *MyType) String() string { return m.value }The Stringer interface type has one method only: String(). Any value that is stored in an interface value Stringer must have this method. We also created a MyType, and we created a method MyType.String() with pointer receiver. This means the String() method is in the method set of the *MyType type, but not in that of MyType.
When we attempt to assign a value of MyType to a variable of type Stringer, we get the error in question:
m := MyType{value: "something"} var s Stringer s = m // cannot use m (type MyType) as type Stringer in assignment: // MyType does not implement Stringer (String method has pointer receiver)But everything is ok if we try to assign a value of type *MyType to Stringer:
s = &m fmt.Println(s)And we get the expected outcome (try it on the Go Playground):
somethingSo the requirements to get this compile-time error:
- A value of non-pointer concrete type being assigned (or passed or converted)
- An interface type being assigned to (or passed to, or converted to)
- The concrete type has the required method of the interface, but with a pointer receiver
Possibilities to resolve the issue:
- A pointer to the value must be used, whose method set will include the method with the pointer receiver
- Or the receiver type must be changed to non-pointer, so the method set of the non-pointer concrete type will also contain the method (and thus satisfy the interface). This may or may not be viable, as if the method has to modify the value, a non-pointer receiver is not an option.
Structs and embedding
When using structs and embedding, often it's not "you" that implement an interface (provide a method implementation), but a type you embed in your struct. Like in this example:
type MyType2 struct { MyType } m := MyType{value: "something"} m2 := MyType2{MyType: m} var s Stringer s = m2 // Compile-time error again
Again, compile-time error, because the method set of MyType2 does not contain the String() method of the embedded MyType, only the method set of *MyType2, so the following works (try it on the Go Playground):
var s Stringer s = &m2
We can also make it work, if we embed *MyType and using only a non-pointer MyType2 (try it on the Go Playground):
type MyType2 struct { *MyType } m := MyType{value: "something"} m2 := MyType2{MyType: &m} var s Stringer s = m2
Also, whatever we embed (either MyType or *MyType), if we use a pointer *MyType2, it will always work (try it on the Go Playground):
type MyType2 struct { *MyType } m := MyType{value: "something"} m2 := MyType2{MyType: &m} var s Stringer s = &m2
Relevant section from the spec (from section Struct types):
So in other words: if we embed a non-pointer type, the method set of the non-pointer embedder only gets the methods with non-pointer receivers (from the embedded type).
If we embed a pointer type, the method set of the non-pointer embedder gets methods with both pointer and non-pointer receivers (from the embedded type).
If we use a pointer value to the embedder, regardless of whether the embedded type is pointer or not, the method set of the pointer to the embedder always gets methods with both the pointer and non-pointer receivers (from the embedded type).
Note:
There is a very similar case, namely when you have an interface value which wraps a value of MyType, and you try to type assert another interface value from it, Stringer. In this case the assertion will not hold for the reasons described above, but we get a slightly different runtime-error:
m := MyType{value: "something"} var i interface{} = m fmt.Println(i.(Stringer))
Runtime panic (try it on the Go Playground):
panic: interface conversion: main.MyType is not main.Stringer: missing method String
Attempting to convert instead of type assert, we get the compile-time error we're talking about:
m := MyType{value: "something"} fmt.Println(Stringer(m))
这篇关于去,X不执行Y(...方法有一个指针接收器)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!