为啥接口不能用指针接收器实现

Posted

技术标签:

【中文标题】为啥接口不能用指针接收器实现【英文标题】:Why can't the interface be implemented with pointer receivers为什么接口不能用指针接收器实现 【发布时间】:2015-08-04 21:16:22 【问题描述】:

我很困惑为什么编译失败:

不可能的类型断言: Faz 没有实现 Foo(Bar 方法有指针接收器)

如果我将 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`

【问题讨论】:

See this post. 附带说明:@KerrekSB 引用的文章有助于我理解当 Go 抱怨“MyFoo 没有实现 Foo(Bar 方法有指针接收器)”时,它没有意味着您不能使用指针接收器。这意味着实现BarMyFoo 方法中的none 应该有指针接收器,或者all 必须有。这与@0xor1 遇到的问题不同,但其他人可能会发现这个问题,因为他们混合了他们的接收器类型(就像我一样)并且不理解他们得到的错误。 【参考方案1】:

因为它是*Faz 而不是Faz

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

【讨论】:

它们可以是 *Faz 或 Faz,但它们都必须匹配。如果您打算 return Faz 或 *Faz 如果您打算 return &Faz ,则将它们全部定义。他们如何维护状态被认为是您基本上对用户隐藏的实现细节。【参考方案2】:

我认为这个问题的答案需要对语法进行更回顾的方法,以及如何通过软件工程来实现它。 (请原谅过于简单化)


首先快速回顾一下types是什么? 它们只是顶部带有编译器逻辑的内存块。使arraystring 不同的是编译器允许我们对这些内存块执行的操作。 (深入思考,您可能会开始意识到strongly typeddynamically typed 语言之间的真正区别。)

接下来你需要意识到指针是它们自己的类型。 *variable 是与variable 不同的内存块(又名类型)。只是编译器始终假定*variable 的内容始终是声明右侧类型的内存块的地址以及它施加的其他限制/功能。

然后让我们回顾一下接口是什么。伪科学定义:任何一等公民必须具有特定类型的一组要求。 转换为软件工程 - 任何具有与合同 (interface) 中描述的相关联的相同内存结构(回想 structure packing)的内存块(类型)都可以传递与合同中提到的类型名称一样。


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

func (f *Faz) Bar() stringf 保存函数的内存块,其中f 的类型是指向Faz 的指针

所在区域

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

所以当你说*Faz 类型的变量满足契约时,你怎么能假设Faz 类型的变量在代码中符合接口类型的条件呢?选择谁满足你的合约,并且只有那个类型可以假设你代码中的接口类型。

【讨论】:

我不同意你的解释,下面的程序工作(类型 *foo 满足 String() 为类型 foo 定义):package main import ("fmt" ) type foo struct func (f foo) String() string return "111" func main() f := foo a := &foo var s fmt.Stringer s = as = f fmt.Println(f.String(), a .String(), s)

以上是关于为啥接口不能用指针接收器实现的主要内容,如果未能解决你的问题,请参考以下文章

为啥要实现Runnable接口,来实现多线程?把Thread作为父类则不能呢?

为啥电脑的蓝牙只能发送文件,而不能接收文件

C#为啥接口可以实例化一个实现该接口的类?

█■为啥要用实现接口的类实例化接口呢?

为啥一个接口不能实现另一个接口?

为啥 PHP Trait 不能实现接口?