在Golang中,我们将结构体与接收器方法结合使用。到这里为止一切都很完美。
我不确定什么是接口。我们在结构中定义方法,如果要在结构上实现方法,则无论如何都要在另一个结构下再次编写该方法。
这意味着接口似乎只是方法定义,仅占用了页面上多余的空间。
有没有解释我为什么需要接口的示例?
接口太大了,不能在这里给出全面的答案,但是有些事情需要弄清楚它们的用途。
接口是一种 工具
。是否使用它们取决于您自己,但是它们可以使代码更清晰,更短,更易读,并且它们可以在程序包,客户端(用户)和服务器(提供者)之间提供良好的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上尝试这些示例。
问题内容: 我们需要大量的序列化工作,并且必须在使用的每个对象上指定标签,这是一种负担。特别是当它是第三方类时,我们不能真正更改。 问题是:由于是一个空接口,并且Java一旦添加便提供了可靠的序列化 为什么它们不使所有内容都可序列化,仅此而已? 问题答案: 序列化充满陷阱。这种形式的自动序列化支持使类内部成为公共API的一部分(这就是javadoc为你提供类的持久化形式的原因)。 为了实现长期持久
问题内容: 在下面的代码中,我展示了我认为在golang中嵌入(提升方法的地方)和组合(提升方法的地方)之间的区别。 为什么要在golang中使用组合? 问题答案: 值得阅读有关“嵌入到有效Go中”的部分。 一个常见的示例是具有Mutex的结构/映射。 打字容易得多 而不是必须编写适当的包装器函数(重复的)或遇到困难 当你将永远做互斥领域的唯一事情就是访问方法(和在这种情况下) 当您尝试在嵌入式字
问题内容: 创建接口方法时,我们不能像在 java中 那样做: 相反,我注意到我们还需要给参数名称lile: 同样,接口实现者不需要具有与接口方法中相同的参数名称。 我在这里发现了有关c#的类似问题。他们提到了 命名参数的一种情况,但是我没有在Java中找到任何其他相关原因。 问题答案: 从技术角度来看,这是没有必要的。 我一直将其作为语法规范化和文档帮助。 这样有: 没有理由区分类和接口方法的语
问题内容: 我知道String [] args是作为参数传递给main的字符串数组。 但是,当您不将其包含为参数时(即使您不使用它),它也会引发异常。那么为什么需要它呢?另外,为什么不能是int []或boolean []? 问题答案: 这是一个字符串,因为命令行以文本形式表示。如果要将文本转换为整数或布尔值,则必须自己做- 操作系统或Java引导程序如何确切知道您希望如何解析所有内容?我想Jav
问题内容: 我可以将数据发送到服务器,但是只有在使用FromBody-Attribute时才可以。 为什么无法使用Post从主体自动读取json数据? 后端Web API 前端angularjs 问题答案: 仅因为某事是POST请求,所以没有明确的规则如何传递参数。POST请求仍可以包含URL中编码的查询参数。方法参数应该是“简单”类型(字符串,整数等)的查询参数。 通常,复杂类型应该是POST表
问题内容: 我正在尝试构建一个简单的React应用程序,并且想知道为什么我需要browser.min.js文件。 我已经包含了react和react-dom.js,但是除非未包含browser.min.js,否则什么也不会显示。 问题答案: 正如您在代码段中看到的那样,script标记的类型为“ text / babel”,这是因为您正在其中使用JSX(带有XML的Javascript)进行编码。