为什么接口不能使用指针接收器来实现?

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

Why can't the interface be implemented with pointer receivers

问题

我对为什么这段代码无法编译通过感到困惑:

如果我将 Faz.Bar 的接收器从 Faz 指针更改为 Faz 值,那么它就可以成功编译。但是我认为最好始终使用指针接收器,这样就不会复制值了。

package main

import (
	"log"
)

func main() {
	foo := New().(Faz)
	log.Println(foo)
}

type Foo interface {
	Bar() string
}

func New() Foo {
	return &Faz{}
}

type Faz struct {
}

func (f *Faz) Bar() string {
	return `Bar`
}
英文:

I'm confused as to why this fails to compile with:

>> impossible type assertion:
>> Faz does not implement Foo (Bar method has pointer receiver)

if I make the receiver for Faz.Bar a Faz value rather than a Faz pointer then it compiles fine, but I thought it was always better to have pointer receivers so values aren't being copied around?

package main

import (
    "log"
)

func main() {
    foo := New().(Faz)
    log.Println(foo)
}

type Foo interface {
    Bar() string
}

func New() Foo {
    return &Faz{}
}

type Faz struct {
}

func (f *Faz) Bar() string {
    return `Bar`
}

答案1

得分: 54

因为它是*Faz而不是Faz

func main() {
    foo := New().(*Faz)
    log.Println(foo)
}
英文:

Because it's *Faz not Faz.

func main() {
    foo := New().(*Faz)
    log.Println(foo)
}

答案2

得分: 4

我认为对这个问题的回答需要更多地回顾语法,并通过软件工程来实现它。(请原谅我过于简化)

首先,让我们快速回顾一下什么是类型?它们只是带有编译器逻辑的内存块。使得数组字符串不同的是编译器允许我们对这些内存块做什么操作。(深入思考,你可能会开始意识到强类型动态类型语言之间的真正区别。)

接下来,你需要意识到指针本身就是一种类型。*变量是一个不同的内存块(也就是类型),与声明右侧的类型相关联,同时还有其他限制/特性。

然后,让我们回顾一下接口是什么。
伪科学定义:对于任何一种特定类型的一等公民来说,它必须满足一组要求。
翻译成软件工程的语言——任何具有与合同(接口)中描述的相同内存结构(回想一下结构打包)的内存块(类型)都可以作为合同所提到的类型名称传递。

现在你可能开始意识到,当你说

func (f *Faz) Bar() string中的f是一个持有函数的内存块,其中f的类型是指向Faz的指针

而当你说

func (f Faz) Bar() string中的f是一个内存块,其中f的类型是Faz

所以当你说一个*Faz类型的变量满足一个合同时,你怎么能假设一个Faz类型的变量在代码中也能作为接口类型呢?选择满足你合同的类型,并且只有该类型才能在你的代码中扮演接口类型的角色。

英文:

I think the answer to this question needs to a more retrospective approach towards the grammar, and how would implement it through software engineering. (Excuse the over simplification)


First a quick flashback of what are types?<br/>
They are just memory blocks with compiler logic on top. What makes an array different from a string is what the compiler allows us to do with those memory blocks. (Think deeper and you may begin to realize the true difference between strongly typed and dynamically typed languages.)

Now next you need to realize that pointers are their own types per say. <br/>*variable is a different memory block (aka type) than variable. It's just that the compiler always assumes that content of *variable is always going to be an address to a memory block of type to the right of the declaration along with other restriction/features it imposes.

Then let's recap what an interface is.<br/>
Pseudo-scientific definition: A set of requirements for any first class citizen to be of a specific type.
Translated to software engineering- any block of memory (types) that has the same memory structure (think back to structure packing) associated to it as described in a contract (interface) can be passed around as with the type name that the contract mentions.


Now you may begin to realize that when you say

func (f *Faz) Bar() string is f's block of memory holding a function, where f's type is a pointer to Faz

where areas

func (f Faz) Bar() string is f's block of memory, where f's type is Faz

So when you are saying that a variable of *Faz type is satisfying a contract, then how can you assume that a variable of Faz type will qualify as interface type in the code? Chose who satisfies your contract, and only that type can assume the interface type in your code.

huangapple
  • 本文由 发表于 2015年5月23日 02:35:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/30403642.html
匿名

发表评论

匿名网友

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

确定