Go语言中用于接口类型的字符串方法

3

我正在解决 The Go Programming Language 这本书中的问题, 在练习7.13中,需要向接口添加String方法。

是否可以向接口添加String()方法?因为数据类型直到运行时才知道。

1个回答

5
添加方法到接口中仅意味着在接口类型定义的方法集合中包含该方法。
例如,这是一个接口:
type Fooer interface {
    Foo()
}

它只有一个方法:Foo()。要将String()方法添加到此接口中:
type Fooer interface {
    Foo()
    String() string
}

完成。我们已将String()方法添加到此接口。

这意味着,如果一个具体类型想要实现这个Fooer接口,以前只需要有一个Foo()方法就足够了。现在还必须有一个String()方法。

另外,请注意,在Go语言中,实现接口是隐式的。没有声明意图的过程。如果一个类型拥有接口的所有方法,则它会隐式地满足该接口。

一个具体类型可能有也可能没有String()方法,与我们的Fooer接口无关。具体类型甚至可能不知道我们的Fooer接口,也不需要知道。

下面是一个实现这个Fooer接口的具体类型:

type fooerImpl int

func (f fooerImpl) Foo() {
    fmt.Printf("Foo() called, I'm %d\n", int(f))
}

func (f fooerImpl) String() string {
    return fmt.Sprintf("Foo[%d]", int(f))
}

测试它:

var f Fooer = fooerImpl(3)
f.Foo()
fmt.Println(f.String())
fmt.Println(f)

输出(在Go Playground上尝试):

Foo() called, I'm 3
Foo[3]
Foo[3]

添加接口方法的后果

如果您随意向接口中添加新方法,可能会导致某些先前实现了该接口的具体类型不再实现它(由于缺少新添加的方法)。

如果这些现有的具体类型被用作接口实例,它们将导致编译时错误,并且在您添加缺失的新方法之前无法正常工作。例如,如果我们从上面的示例中删除fooerImpl.String()方法,则代码var f Fooer = fooerImpl(3)会导致编译时错误:

cannot use fooerImpl(3) (type fooerImpl) as type Fooer in assignment:
    fooerImpl does not implement Fooer (missing String method)

如果现有的具体类型没有直接用作接口实例,而是通过包装在空接口interface{}中传递,并使用type assertion提取接口的值,则这些类型断言将不再有效。类型断言的“简单”形式x.(T)将导致运行时恐慌,特殊形式v, ok := x.(T)将返回nilfalse
例如,在没有String()方法的情况下使用上述的fooerImpl类型:
var f0 interface{} = fooerImpl(3)
f := f0.(Fooer)

运行时恐慌的结果:

panic: interface conversion: main.fooerImpl is not main.Fooer: missing method String

并使用特殊的类型转换形式:

if f, ok := f0.(Fooer); ok {
    f.Foo()
} else {
    fmt.Println("Not instance of Fooer!", f)
}

结果为:

Not instance of Fooer! <nil>

如果现有的具体类型已经有一个你刚刚添加到接口中并且具有相同签名(相同参数和返回类型)的方法,那么很好,具体类型也将“继续”实现新接口。 如果签名不匹配(例如,现有方法具有不同的返回类型),则它将无法满足接口,并且与没有具有相同名称的方法相同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接