接口太大了,不能在这里给出全面的答案,但是有些事情需要弄清楚它们的用途。
接口是一种 工具
。是否使用它们取决于您自己,但是它们可以使代码更清晰,更短,更易读,并且它们可以在程序包,客户端(用户)和服务器(提供者)之间提供良好的API。
是的,您可以创建自己的
struct类型,并且可以“附加”方法,例如:
type Cat struct{}func (c Cat) Say() string { return "meow" }type Dog struct{}func (d Dog) Say() string { return "woof" }func main() { c := Cat{} fmt.Println("Cat says:", c.Say()) d := Dog{} fmt.Println("Dog says:", d.Say())}
我们已经在上面的代码中看到了一些重复:在使两者
Cat同时
Dog说话时。我们可以像 对待动物
一样对待两者吗?并不是的。当然,我们可以将两者都作为处理
interface{},但是如果这样做,则不能调用它们的
Say()方法,因为type的值
interface{}未定义任何方法。
上面的两种类型都有一些 相似之处 :两者都具有
Say()签名相同的方法(参数和结果类型)。我们可以通过一个接口 捕获 它:
type Sayer interface { Say() string}
接口仅包含方法的 签名 ,而不包含方法的 实现 。
请注意,在Go语言中,如果类型的方法集是该接口的超集,则该类型 隐式
实现该接口。没有意图的声明。这是什么意思?我们以前
Cat和
Dog类型已经实现了这个
Sayer接口,即使在我们前面写了他们这个接口定义根本不存在,而我们没有接触他们,以纪念他们什么。他们只是做。
接口指定行为 。实现接口的类型意味着该类型具有接口“规定”的所有方法。
由于两者都实现了
Sayer,我们可以将两者都当作的值来处理
Sayer,因此它们具有相同的地方。看看我们如何统一处理这两个问题:
animals := []Sayer{c, d}for _, a := range animals { fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say())}
(这反映出部分只是为了获得类型名称,到目前为止还不多。)
最重要的部分是,我们可以同时处理
Cat并
Dog视为同类(接口类型),并与他们合作/使用它们。如果您很快要使用
Say()方法创建其他类型,则可以在
Cat和旁边排队
Dog:
type Horse struct{}func (h Horse) Say() string { return "neigh" }animals = append(animals, Horse{})for _, a := range animals { fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say())}
假设您要编写其他适用于这些类型的代码。辅助功能:
func MakeCatTalk(c Cat) { fmt.Println("Cat says:", c.Say())}
是的,上面的函数可以使用
Cat,也可以不使用。如果您想要类似的东西,则必须为每种类型编写它。不用说这有多糟。
是的,您可以编写它来接受的参数
interface{},并使用类型断言或类型开关,这将减少辅助函数的数量,但看起来仍然很丑陋。
解决方案?是的,界面。只需声明该函数以采用接口类型的值即可,该接口类型定义了您要对其执行的 *** 作,仅此而已:
func MakeTalk(s Sayer) { fmt.Println(reflect.TypeOf(s).Name(), "says:", s.Say())}
你可以调用这个函数的值
Cat,
Dog,
Horse或任何其他类型的现在不知道,直到,有一个
Say()方法。凉。
在Go Playground上尝试这些示例。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)