在处理接口时,类型断言是返回结构指针的唯一方法吗?

Lau*_*ent 0 methods interface go type-assertion

考虑以下代码:

package main

import "fmt"
// 5
type I interface {
    Foo() string
}

type a struct {
    i int
}

func (s a) Foo() string {
    return "We are here!"
}

func (s a) Bar() string {
    return "Major Tom!"
}
// 20
func main() {
    var x I = &a{i: 42}
    fmt.Println(x.Foo())
    fmt.Println(x.(*a).Bar())
}
Run Code Online (Sandbox Code Playgroud)

main 的最后一个语句给了我底层结构,但我需要导出这个结构才能返回它。

如果我在库中使用一个包,其中导出的唯一符号是接口(在上面的示例中,第 5-20 行之间是大 I,小 a),那么当我处于另一个包或文件。

由于原始结构存储在接口中,是否有一种简单的方法来获取其引用并使用尚未在接口中声明且仅附加到结构的方法。

icz*_*cza 5

是的,在一般情况下,您需要类型断言(或类型 switch)来获取接口值中的包装值。

但是您不需要从接口取回存储的具体值就能够调用它具有的其他方法(并且这些方法不属于接口类型的一部分)。

您可以从一个接口值类型断言另一个接口值,另一个接口值的类型包含您想要调用的方法。

看这个例子:

type Foo interface {
    Bar() string
}

type fooImpl struct{}

func (fooImpl) Bar() string { return "Bar from fooImpl" }

func (fooImpl) Baz() string { return "Baz from fooImpl" }

func main() {
    var f Foo = &fooImpl{}

    if x, ok := f.(interface{ Baz() string }); ok {
        fmt.Println(x.Baz())
    } else {
        fmt.Println("f does not have a Baz() method!")
    }
}
Run Code Online (Sandbox Code Playgroud)

Foo只有一个Bar()方法。我们有一个f类型为 的变量Foo,它存储的具体类型是*fooImpl,它还有另一个方法:fooImpl.Baz()

interface{ Baz() string }因此,我们可以通过类型断言它的类型值,然后简单地调用Baz()结果。

上面的输出是(在Go Playground上尝试一下):

Baz from fooImpl
Run Code Online (Sandbox Code Playgroud)

从另一个接口值对接口进行类型断言不需要导出包装值的类型。

您还可以为您键入assert的接口类型创建一个新类型,匿名类型不是必需的:

type MyFoo interface{ Baz() string }

if x, ok := f.(MyFoo); ok {
    fmt.Println(x.Baz())
} else {
    fmt.Println("f does not have a Baz() method!")
}
Run Code Online (Sandbox Code Playgroud)

输出是相同的(在Go Playground上尝试一下)。

天哪,您甚至可以Foo使用附加方法“扩展”,并类型断言“扩展”接口:

type MyFoo interface {
    Foo
    Baz() string
}

if x, ok := f.(MyFoo); ok {
    fmt.Println(x.Bar())
    fmt.Println(x.Baz())
} else {
    fmt.Println("f does not have a Baz() method!")
}
Run Code Online (Sandbox Code Playgroud)

现在,在这个示例中x,aFoo和值都有一个Baz()方法。输出(在Go Playground上尝试):

Bar from fooImpl
Baz from fooImpl
Run Code Online (Sandbox Code Playgroud)