为啥直接实现的接口上的这种类型断言会失败?

Posted

技术标签:

【中文标题】为啥直接实现的接口上的这种类型断言会失败?【英文标题】:Why does this Type Assertion on a direct implemented interface fail?为什么直接实现的接口上的这种类型断言会失败? 【发布时间】:2019-03-15 08:26:02 【问题描述】:

我正在为 Go 的类型断言机制而苦苦挣扎。在下面的示例中,Qux.(Bar) 的类型断言失败。

为什么在Qux 直接实现DoBar() 不能完全填充Bar 接口?

主包

import (
    "fmt"
)

type Nameable interface 
    Name() string


type Foo interface 
    Nameable
    DoFoo() string


type Bar interface 
    Nameable
    DoBar() string


type bar struct 
    name string


func (b bar) Name() string 
    return b.name


// Qux embeds bar and is expected to fullfill Nameable interface
type Qux struct 
    bar


func (q *Qux) DoBar() string 
    return "DoBar"


func Check(subject Nameable) 
    if N, ok := subject.(Nameable); ok 
        fmt.Printf("%s has Nameable\n", N.Name())
     

    if F, ok := subject.(Foo); ok 
        fmt.Printf("%s has Foo: %s\n", F.Name(), F.DoFoo())
    

    if B, ok := subject.(Bar); ok 
        fmt.Printf("%s has Bar: %s\n", B.Name(), B.DoBar())
    


func main() 
    Check(barname: "bar")
    Check(Quxbar: barname: "Qux")

https://play.golang.org/p/PPkUMUu58JW

输出:

bar has Nameable
Qux has Nameable

【问题讨论】:

只有 *CUx 有 DoBar。停止尝试通过嵌入来模拟继承。嵌入只是语法糖。写出嵌入,你会看到。 @Volker 但是Qux 在类型断言subject.(Bar) 上失败,尽管它实现了DoBar() 本身?! 不,它没有 DoBar 方法。 【参考方案1】:

Qux.DoBar() 有指针接收器,所以只有*Qux 实现了Bar 而不是Qux。类型Qux 和指向它的指针类型*Qux 是不同的类型,具有不同的method sets。

使用*Qux 类型的值确实实现Bar

Check(&Quxbar: barname: "*Qux")

这个输出(在Go Playground上试试):

*Qux has Nameable
*Qux has Bar: DoBar

另外,如果您将Qux.DoBar() 的接收者更改为非指针:

func (q Qux) DoBar() string 
    return "DoBar"

那么Qux*Qux 都会实现Bar

Check(barname: "bar")
Check(Quxbar: barname: "Qux")
Check(&Quxbar: barname: "*Qux")

输出(在Go Playground上试试):

bar has Nameable
Qux has Nameable
Qux has Bar: DoBar
*Qux has Nameable
*Qux has Bar: DoBar

查看相关问题:X does not implement Y (... method has a pointer receiver)

【讨论】:

谢谢你,@icza。

以上是关于为啥直接实现的接口上的这种类型断言会失败?的主要内容,如果未能解决你的问题,请参考以下文章

golang类型断言的使用(Type Assertion)

接口——定义,实现接口的条件,类型与接口的关系,类型断言

为啥 TypeScript 中的方法链接会导致泛型类型推断失败?

带有指针的 Golang 类型断言

UICollectionView 上的断言失败

go语言接口断言