4

Go 语言具有接口类型作为特性,类似于 C 风格的接口。然而,Go 的接口类型似乎并没有被强制执行——它们只是定义协议而不实际应用于类型。由于它们没有被强制执行,使用接口仍然是一个好主意吗?

4

3 回答 3

10

是的。Go 不允许您构建类型层次结构,因此接口对于允许某些多态性非常重要。考虑sort.Interface包中定义的sort

type Interface interface {
    // Len is the number of elements in the collection.
    Len() int
    // Less returns whether the element with index i should sort
    // before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

sort包包含一个函数,该函数sort(data Interface)需要任何实现此接口的对象。如果没有接口,这种形式的多态性在 Go 中是不可能的。您不必显式注释您的类型实现此接口这一事实是无关紧要的。

go 最酷的部分是你甚至可以在原始类型上实现这个接口,只要类型定义在同一个包中。所以下面的代码定义了一个可排序的整数数组:

type Sequence []int

// Methods required by sort.Interface.
func (s Sequence) Len() int {
    return len(s)
}
func (s Sequence) Less(i, j int) bool {
    return s[i] < s[j]
}
func (s Sequence) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}
于 2012-06-15T16:50:30.067 回答
3

是的,使用接口仍然是一个好主意。Go 强调接口。请参阅https://talks.golang.org/2014/go4gophers.slide#5。扩展@ElianEbbing 出色的答案,任何类型的方法和临时接口都形成了一种轻量级的OO 编程风格。见https://talks.golang.org/2012/goforc.slide#48

一个例子可以说明这一点。

package main

import . "fmt"

func main() {
    c.Cry()      // Meow
    Cryer.Eat(c) // Fish
}

var c = cat{"Fish"}
type cat struct{ s string }
type Eater interface{ Eat() }
type Cryer interface {
    Cry()
    Eater
}
func (c cat) Eat() { Println(c.s) }
func (cat) Cry()   { Println("Meow") }

Cryer接口允许您访问Cry()Eat()方法。请参阅https://talks.golang.org/2012/zen.slide#16。您可以在Cryer不更改的情况下添加到底层代码。请参阅https://stackoverflow.com/a/11753508/12817546。如果我们删除它,代码就可以正常工作。您仍然可以直接访问方法,如 所示c.Cry()。这是因为 Go 允许你做两件事。

首先,您可以隐式实现接口。接口只是一组方法。请参阅https://talks.golang.org/2013/go4python.slide#33​​ 。接口变量可以存储任何非接口值,只要它实现了接口的方法。请参阅https://blog.golang.org/laws-of-reflection。实现接口的所有方法的任何类型的值都可以分配给该接口的变量。请参阅https://talks.golang.org/2014/taste.slide#20

c是 的一个变量catcat实现Eat()andCry()方法。Eater明确实现Eat(). Cryer显式实现Cry()and Eat()。因此cat隐式实现了EaterandCryer接口。请参阅https://talks.golang.org/2012/goforc.slide#40。因此c,变量 ofcat可以是Eater和的变量Cryer。请参阅https://golang.org/doc/effective_go.html#blank_implements

其次,结构和接口类型可以嵌入到其他结构和接口类型中。请参阅https://golang.org/doc/effective_go.html#embeddingCryer.Eat(c)调用Eat(),因为它嵌入Eater. 因此,Go 中的接口是解耦程序组件的主要手段。请参阅https://www.reddit.com/r/golang/comments/6rwq2g。以及为什么接口可以在包、客户端或服务器之间提供一个很好的 API。请参阅https://stackoverflow.com/a/39100038/12817546

如果您没有看到好处,请不要添加接口。请参阅https://stackoverflow.com/a/39100038/12817546中的评论。没有明确的层次结构,因此不需要设计一个!请参阅https://talks.golang.org/2012/goforc.slide#46。需要时添加接口。首先定义您的数据类型,然后构建您的 1-3 种方法interface。请参阅https://stackoverflow.com/a/11753508/12817546。报价已编辑以匹配示例。

于 2020-06-10T07:12:58.617 回答
0

我希望知道静态和运行时的类型检查是什么,但我不知道什么是“强制接口”。

于 2012-06-15T16:53:38.097 回答