x不实现y(...方法具有指针接收器)

发布于 2025-01-24 16:06:56 字数 202 浏览 0 评论 0 原文

已经有几个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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小嗲 2025-01-31 16:06:56

当您尝试分配或通过(或转换) Concrete 类型为接口类型时,会出现此编译时错误;并且类型本身不会实现接口,只有指向类型的指针。

简短摘要: an 分配到接口类型的变量如果被分配的值实现其分配给的接口,则有效。如果它的方法集是接口的超级集,则可以实现它。指针类型的方法集包括使用 指针和非点接收器的方法。非销钉类型的方法集唯一包括带有非销钉接收器的方法。

让我们看看一个示例:

type Stringer interface {
    String() string
}

type MyType struct {
    value string
}

func (m *MyType) String() string { return m.value }

stringer 接口类型只有一个方法:<代码>字符串()。在接口值 stringer 中存储的任何值都必须具有此方法。我们还创建了一个 myType ,并使用 Pointer 接收器创建了一个方法 myType.string()。这意味着 string()方法在*myType 类型,但不在 mytype 中。

当我们尝试将 myType 的值分配给类型 stringer 的变量时,我们会收到问题的错误:

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)

但是,如果我们尝试分配类型的值,一切都还好*myType to stringer

s = &m
fmt.Println(s)

我们获得了预期的结果(在 Go Playground ):

something

因此,要分配此编译时错误的要求:

  • non-Pointer 混凝土类型的值传递或转换)
  • 被分配给(或传递给或转换为)
  • 混凝土类型的接口类型具有接口所需的方法,但是使用 Pointer接收器

解决问题的可能性:

  • 必须使用指向值的指针,其方法集将包括指针接收器
  • 或接收器类型必须更改为 non-pointer ,因此非销钉混凝土类型还将包含该方法(因此满足接口)。这可能是或可能不可行的,好像该方法必须修改该值一样,非分子接收器不是一个选项。

使用结构并嵌入

,通常不是实现界面(提供界面(提供))方法实现),但是您嵌入 struct 中的一种类型。像在此示例中:

type MyType2 struct {
    MyType
}

m := MyType{value: "something"}
m2 := MyType2{MyType: m}

var s Stringer
s = m2 // Compile-time error again

再次,编译时间错误,因为 myType2 的方法集不包含嵌入式 myType string()方法>,只有*myType2 的方法集,因此以下工作(在 GO Playground ):

var s Stringer
s = &m2

如果我们嵌入*myType ,并且仅使用 non-pointer myType2

type MyType2 struct {
    *MyType
}

m := MyType{value: "something"}
m2 := MyType2{MyType: &m}

var s Stringer
s = m2

(在 Go Playground 上尝试一下 /code>或*myType ),如果我们使用指针*myType2 ,它将始终工作(在 go playground ):

type MyType2 struct {
    *MyType
}

m := MyType{value: "something"}
m2 := MyType2{MyType: &m}

var s Stringer
s = &m2

Spec的相关部分(来自 struct类型):

给定一个结构类型 s 和一种名为 t 的类型,促进的方法包含在结构的方法集中,如下所示:

  • 如果 s 包含一个匿名字段 t ,则 s 的方法集*s 都包括proporteded带有接收器的方法 t *S 的方法集还包括带有接收器*t 的促进方法。
  • 如果 s 包含一个匿名字段*t ,则 s 的方法集*s 都包括使用接收器的促进方法 t *t

因此,换句话说:如果我们嵌入了非分子类型,则非分子嵌入式的方法集仅获取具有非销钉接收器的方法(来自嵌入式类型)。

如果我们嵌入了指针类型,则非指针嵌入器的方法集使用指针和非点接收器(来自嵌入式类型)。

如果我们对嵌入器使用指针值,无论嵌入式类型是否为指针,指向嵌入器的指针的方法集总是使用指针和非指针接收器(来自嵌入式类型)获取方法。

注意:

有一个非常相似的情况,即,当您具有包装 myType 的接口值时,您尝试 type surstert 来自它的另一个接口值, stringer 。在这种情况下,由于上述原因,断言将无法持有,但是我们会得到略有不同的运行时间:

m := MyType{value: "something"}

var i interface{} = m
fmt.Println(i.(Stringer))

运行时恐慌(在 go playground ):

panic: interface conversion: main.MyType is not main.Stringer:
    missing method String

尝试转换而不是类型sostert,我们会收到我们正在谈论的编译时间错误:

m := MyType{value: "something"}

fmt.Println(Stringer(m))

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:

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):

something

So 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):

Given a struct type S and a type named T, promoted methods are included in the method set of the struct as follows:

  • If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
  • If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T.

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))
夜深人未静 2025-01-31 16:06:56

为了使其简单简单,可以说您拥有一个实现此接口的加载程序接口和一个Webloader。

package main

import "fmt"

// Loader defines a content loader
type Loader interface {
    load(src string) string
}

// WebLoader is a web content loader
type WebLoader struct{}

// load loads the content of a page
func (w *WebLoader) load(src string) string {
    return fmt.Sprintf("I loaded this page %s", src)
}

func main() {
    webLoader := WebLoader{}
    loadContent(webLoader)
}

func loadContent(loader Loader) {
    loader.load("google.com")
}

以上代码将为您带来此编译时间错误

./ main.go:20:13:无法将Webloader(键入Webloader)用作类型加载程序
在loadContent的争论中:
Webloader不实现加载程序(加载方法具有指针接收器)

来修复它,您只需要更改 webloader:= webloader {} to以下:

webLoader := &WebLoader{} 

为什么这会解决问题?因为您定义了此功能 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.

package main

import "fmt"

// Loader defines a content loader
type Loader interface {
    load(src string) string
}

// WebLoader is a web content loader
type WebLoader struct{}

// load loads the content of a page
func (w *WebLoader) load(src string) string {
    return fmt.Sprintf("I loaded this page %s", src)
}

func main() {
    webLoader := WebLoader{}
    loadContent(webLoader)
}

func loadContent(loader Loader) {
    loader.load("google.com")
}

The above code will give you this compile time error

./main.go:20:13: cannot use webLoader (type WebLoader) as type Loader
in argument to loadContent:
WebLoader does not implement Loader (Load method has pointer receiver)

To fix it you only need to change webLoader := WebLoader{} to following:

webLoader := &WebLoader{} 

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

温折酒 2025-01-31 16:06:56

当我看到这种事情发生的另一种情况是,如果我想创建一个接口,某些方法会修改内部值,而其他方法则不会。

type GetterSetter interface {
   GetVal() int
   SetVal(x int) int
}

然后实现此界面的某些内容可能是这样的:

type MyTypeA struct {
   a int
}

func (m MyTypeA) GetVal() int {
   return a
}

func (m *MyTypeA) SetVal(newVal int) int {
    int oldVal = m.a
    m.a = newVal
    return oldVal
}

因此,实现类型可能会有一些方法是指针接收器,而有些则不是,并且由于我有很多这些都是getTersetters,我想在我的身上检查一下测试他们都在做预期的。

如果我要做这样的事情:

myTypeInstance := MyType{ 7 }
... maybe some code doing other stuff ...
var f interface{} = myTypeInstance
_, ok := f.(GetterSetter)
if !ok {
    t.Fail()
}

那么我将不会得到上述“ x不实现y(z方法具有指针接收器)”错误(因为这是一个编译时错误),但是i will 糟糕的一天要追逐为什么我的测试失败了……

相反,我必须确保我使用指针进行检查,例如:

var f interface{} = new(&MyTypeA)
 ...

或:

myTypeInstance := MyType{ 7 }
var f interface{} = &myTypeInstance
...

所有人都对测试感到满意!

但是等等!在我的代码中,也许我有可以在某个地方接受gettersetter的方法:

func SomeStuff(g GetterSetter, x int) int {
    if x > 10 {
        return g.GetVal() + 1
    }
    return g.GetVal()
}

如果我从其他类型的方法中调用这些方法,则会生成错误:

func (m MyTypeA) OtherThing(x int) {
    SomeStuff(m, x)
}

以下任何一个调用都会起作用:

func (m *MyTypeA) OtherThing(x int) {
    SomeStuff(m, x)
}

func (m MyTypeA) OtherThing(x int) {
    SomeStuff(&m, x)
}

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.

type GetterSetter interface {
   GetVal() int
   SetVal(x int) int
}

Something that then implements this interface could be like:

type MyTypeA struct {
   a int
}

func (m MyTypeA) GetVal() int {
   return a
}

func (m *MyTypeA) SetVal(newVal int) int {
    int oldVal = m.a
    m.a = newVal
    return oldVal
}

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:

myTypeInstance := MyType{ 7 }
... maybe some code doing other stuff ...
var f interface{} = myTypeInstance
_, ok := f.(GetterSetter)
if !ok {
    t.Fail()
}

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:

var f interface{} = new(&MyTypeA)
 ...

Or:

myTypeInstance := MyType{ 7 }
var f interface{} = &myTypeInstance
...

Then all is happy with the tests!

But wait! In my code, perhaps I have methods which accept a GetterSetter somewhere:

func SomeStuff(g GetterSetter, x int) int {
    if x > 10 {
        return g.GetVal() + 1
    }
    return g.GetVal()
}

If I call these methods from inside another type method, this will generate the error:

func (m MyTypeA) OtherThing(x int) {
    SomeStuff(m, x)
}

Either of the following calls will work:

func (m *MyTypeA) OtherThing(x int) {
    SomeStuff(m, x)
}

func (m MyTypeA) OtherThing(x int) {
    SomeStuff(&m, x)
}
百合的盛世恋 2025-01-31 16:06:56

从上述答案延伸(感谢您的所有答案)
我认为显示所有指针 /非指针结构的方法将是更本能的。

这是操场代码。
https://play.golang.org/p/jkyrqf4kyif

用于总结所有示例。

  1. 指针结构类型将包括所有非指针 /指针接收器方法
  2. 非指针结构类型仅包括非指针接收器方法。

对于嵌入式结构

  1. 非指针外部结构 +非指针嵌入式struct =&gt;仅非指针接收器方法。
  2. 非指针外部结构 +指针嵌入结构 /指针外部结构 +非指针嵌入式结构 /指针外部结构 +指针嵌入结构=&gt;所有嵌入式方法

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.

  1. Pointer struct type would include all non pointer / pointer receiver methods
  2. Non pointer struct type would only include non pointer receiver methods.

For embedded struct

  1. non pointer outer struct + non pointer embedded struct => only non pointer receiver methods.
  2. non pointer outer struct + pointer embedded struct / pointer outer struct + non pointer embedded struct / pointer outer struct + pointer embedded struct => all embedded methods
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文