已经有几个Q&如此“ x”没有实现y(...方法有一个指针接收器)“东西,但对我来说,他们似乎在谈论不同的事情,而不是在谈论不同的事情,而不是适用于我的具体情况。
因此,我并没有将问题非常具体,而是使它变得广泛而抽象 - 似乎有几种不同的情况可以使此错误发生,有人可以摘要吗?
即,如何避免问题,如果发生问题,可能性是什么?谢谢。
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.
发布评论
评论(4)
当您尝试分配或通过(或转换) Concrete 类型为接口类型时,会出现此编译时错误;并且类型本身不会实现接口,只有指向类型的指针。
简短摘要: an 分配到接口类型的变量如果被分配的值实现其分配给的接口,则有效。如果它的方法集是接口的超级集,则可以实现它。指针类型的方法集包括使用 指针和非点接收器的方法。非销钉类型的方法集唯一包括带有非销钉接收器的方法。
让我们看看一个示例:
stringer
接口类型只有一个方法:<代码>字符串()。在接口值stringer
中存储的任何值都必须具有此方法。我们还创建了一个myType
,并使用 Pointer 接收器创建了一个方法myType.string()
。这意味着string()
方法在*myType 类型,但不在mytype
中。当我们尝试将
myType
的值分配给类型stringer
的变量时,我们会收到问题的错误:但是,如果我们尝试分配类型的值,一切都还好
*myType
tostringer
:我们获得了预期的结果(在 Go Playground ):
因此,要分配此编译时错误的要求:
解决问题的可能性:
使用结构并嵌入
,通常不是实现界面(提供界面(提供))方法实现),但是您嵌入
struct
中的一种类型。像在此示例中:再次,编译时间错误,因为
myType2
的方法集不包含嵌入式myType string()
方法>,只有*myType2
的方法集,因此以下工作(在 GO Playground ):如果我们嵌入
*myType
,并且仅使用 non-pointermyType2
。(在 Go Playground 上尝试一下 /code>或
*myType
),如果我们使用指针*myType2
,它将始终工作(在 go playground ):Spec的相关部分(来自 struct类型):
因此,换句话说:如果我们嵌入了非分子类型,则非分子嵌入式的方法集仅获取具有非销钉接收器的方法(来自嵌入式类型)。
如果我们嵌入了指针类型,则非指针嵌入器的方法集使用指针和非点接收器(来自嵌入式类型)。
如果我们对嵌入器使用指针值,无论嵌入式类型是否为指针,指向嵌入器的指针的方法集总是使用指针和非指针接收器(来自嵌入式类型)获取方法。
注意:
有一个非常相似的情况,即,当您具有包装
myType
的接口值时,您尝试 type surstert 来自它的另一个接口值,stringer
。在这种情况下,由于上述原因,断言将无法持有,但是我们会得到略有不同的运行时间:运行时恐慌(在 go playground ):
尝试转换而不是类型sostert,我们会收到我们正在谈论的编译时间错误:
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.
Short summary: An assignment to a variable of interface type is valid if the value being assigned implements the interface it is assigned to. It implements it if its method set is a superset of the interface. The method set of pointer types includes methods with both pointer and non-pointer receiver. The method set of non-pointer types only includes methods with non-pointer receiver.
Let's see an example:
The
Stringer
interface type has one method only:String()
. Any value that is stored in an interface valueStringer
must have this method. We also created aMyType
, and we created a methodMyType.String()
with pointer receiver. This means theString()
method is in the method set of the*MyType
type, but not in that ofMyType
.When we attempt to assign a value of
MyType
to a variable of typeStringer
, we get the error in question:But everything is ok if we try to assign a value of type
*MyType
toStringer
:And we get the expected outcome (try it on the Go Playground):
So the requirements to get this compile-time error:
Possibilities to resolve the issue:
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:Again, compile-time error, because the method set of
MyType2
does not contain theString()
method of the embeddedMyType
, only the method set of*MyType2
, so the following works (try it on the Go Playground):We can also make it work, if we embed
*MyType
and using only a non-pointerMyType2
(try it on the Go Playground):Also, whatever we embed (either
MyType
or*MyType
), if we use a pointer*MyType2
, it will always work (try it on the Go Playground):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:Runtime panic (try it on the Go Playground):
Attempting to convert instead of type assert, we get the compile-time error we're talking about:
为了使其简单简单,可以说您拥有一个实现此接口的加载程序接口和一个Webloader。
以上代码将为您带来此编译时间错误
来修复它,您只需要更改
webloader:= webloader {}
to以下:为什么这会解决问题?因为您定义了此功能
func(W *Webloader)加载
以接受指针接收器。有关更多说明,请阅读@icza和@karora答案To keep it short and simple, let say you have a Loader interface and a WebLoader that implements this interface.
The above code will give you this compile time error
To fix it you only need to change
webLoader := WebLoader{}
to following:Why this will fix the issue? Because you defined this function
func (w *WebLoader) Load
to accept a pointer receiver. For more explanation please read @icza and @karora answers当我看到这种事情发生的另一种情况是,如果我想创建一个接口,某些方法会修改内部值,而其他方法则不会。
然后实现此界面的某些内容可能是这样的:
因此,实现类型可能会有一些方法是指针接收器,而有些则不是,并且由于我有很多这些都是getTersetters,我想在我的身上检查一下测试他们都在做预期的。
如果我要做这样的事情:
那么我将不会得到上述“ x不实现y(z方法具有指针接收器)”错误(因为这是一个编译时错误),但是i will 糟糕的一天要追逐为什么我的测试失败了……
相反,我必须确保我使用指针进行检查,例如:
或:
所有人都对测试感到满意!
但是等等!在我的代码中,也许我有可以在某个地方接受gettersetter的方法:
如果我从其他类型的方法中调用这些方法,则会生成错误:
以下任何一个调用都会起作用:
Another case when I have seen this kind of thing happening is if I want to create an interface where some methods will modify an internal value and others will not.
Something that then implements this interface could be like:
So the implementing type will likely have some methods which are pointer receivers and some which are not and since I have quite a variety of these various things that are GetterSetters I'd like to check in my tests that they are all doing the expected.
If I were to do something like this:
Then I won't get the aforementioned "X does not implement Y (Z method has pointer receiver)" error (since it is a compile-time error) but I will have a bad day chasing down exactly why my test is failing...
Instead I have to make sure I do the type check using a pointer, such as:
Or:
Then all is happy with the tests!
But wait! In my code, perhaps I have methods which accept a GetterSetter somewhere:
If I call these methods from inside another type method, this will generate the error:
Either of the following calls will work:
从上述答案延伸(感谢您的所有答案)
我认为显示所有指针 /非指针结构的方法将是更本能的。
这是操场代码。
https://play.golang.org/p/jkyrqf4kyif
用于总结所有示例。
对于嵌入式结构
Extend from above answers (Thanks for all of your answers)
I think it would be more instinctive to show all the methods of pointer / non pointer struct.
Here is the playground code.
https://play.golang.org/p/jkYrqF4KyIf
To summarize all the example.
For embedded struct