请教各位 go 语言大佬一个问题

2022-04-11 11:54:45 +08:00
 yunshangdetianya
go 语言中的接口与方法的区别
结构体 A ,拥有方法 run
结构体 B ,拥有方法 run
接口 C ,内部有一个方法 run
那么我调用 run 方法时候,可以直接 A.run ,或则 B.run 不就行了
为何还要定义一个接口变量,然后实例化这个变量,再调用方法?这不是多此一举吗?伪代码如下
var x C
x=A{}
x.run
x=B{}
x.run()
我直接
x :=A{}
x.run()
或者
x :=B{}
b.run()
感觉弄一个接口不是多此一举吗?
初学 go ,往大家多多解惑
3791 次点击
所在节点    Go 编程语言
31 条回复
yunshangdetianya
2022-04-11 16:37:17 +08:00
@BeautifulSoap 非常感谢你的详细解答,我看了你的解答后好像明白点了,接口作用就是限制和约束类型
yunshangdetianya
2022-04-11 16:39:12 +08:00
@BrightSphere 通用性
FanGanXS
2022-04-11 17:26:16 +08:00
type notify interface {
send()
}

// Email 实现 1
type Email struct{}

func (Email) send() {
fmt.Println("email send")
}

// Qq 实现 2
type Qq struct{}

func (Qq) send() {
fmt.Println("qq send")
}

func Test(n notify) {
n.send()
}

假如说我现在需要实现一个通知的功能,但是我并不想具体采用哪种方式发通知(比如,微信、电子邮箱、QQ ),所以我就实现一个 notify 接口,它是通知的抽象(并没有具象到具体的采用哪放方式来实现通知)。接下来我利用 Emali 和 Qq 来对这个 notify 接口进行了实现,它们是这个抽象的具象。那么在外部调用的时候,我并不需要关心我具体使用哪种通知方式来发起通知,我只需要实现通知(就好像,老板通知你完成某一件事情,但是老板并不需要知道你完成某件事情的过程,采用哪种方式,他只想要这件事情的结果,而 Email 是同事 A 的完成方式,Qq 是同事 B 的完成方式,最后老板采用哪位同事来处理这件事情,是由老板自己决定,老板只需要指定某个同事就可以了)。即
func main() {
person.Test(&person.Qq{})
}

func main() {
person.Test(&person.Email{})
}
konnnnn
2022-04-11 17:47:37 +08:00
Python Oop => poop
concernedz
2022-04-11 17:51:26 +08:00
@droppedbytech duck type
raaaaaar
2022-04-11 21:10:41 +08:00
多态、面向抽象而不是实现、接口和实现的解耦等等,写个需要设计的轮子就懂了
GeruzoniAnsasu
2022-04-11 23:13:03 +08:00
@yunshangdetianya

> 接口作用就是限制和约束类型

正相反。

静态类型语言的变量,类型是「唯一的」。你可能一下 get 不到有多唯一,我举个自己初学 oop 时对我帮助很大的例子

- 你的程序有两个窗口
- 窗口 A 叫 A ,B 叫<嘎>
- 你给窗口 A 声明了一个类型 type WindowA struct{ Title: A }
- 窗口 B 的类型 type WindowB struct{ Title: <嘎> }

现在你想判断鼠标点击了哪个窗口:

func findWhichClicked(x,y int) (T){}

问题来了: 应该返回什么类型?返回 A ,那么点到 B 这个函数就给不出数据了,反之亦然。
那……返回他们的公共类型?

type WindowA{Window; Title }
type WindowB{Window; Title }// AB 都来自 Window
func findWhich(x,y int) (w Window){}

但还是有问题: 我想获得点到的窗口的标题:

w := findWhich()
w.Title() // ?

做不到!
我永远只能获得 Window 的标题, 不能获得 WindowA 或者 WindowB 的标题。

「这事简直跟我是男人了就不是人了一样荒唐」!!


你可能会疑惑了,那用个公共变量呗

if inA() {w=windowA}
else if inB(){w=windowB} // 类型不匹配!,无法将 WindowA 类型的变量赋值给 Window 类型




------


接口:
type <有 title> interface {Title() }
func findWhichClicked(x,y int) <有 title> {} // windowA 和 windowB 都可以实现 <有 title>
w.Title() // w 可以是任何 <有 title>类型,运行期决定

如果 w 是 windowA ,那么调用 windowA 的实现,是 B 调用 B 的实现。





------


想想这句话: 「我要使用一个变量,它可能代表不同的东西,但类型又得是唯一的」
tpkeeper
2022-04-12 00:48:28 +08:00
优点:
1 后期维护方便,可以针对接口扩展实现不同的实例
2 减少 package 之间的依赖,避免循环引用,大型项目中很有用
afewok
2022-04-12 08:05:31 +08:00
这不就是多态?
tairan2006
2022-04-12 10:12:36 +08:00
其实一般是为了单元测试 mock 才这么搞……如果不强调单元测试覆盖率,倒也不用处处这么玩。
qq1009479218
2022-04-12 10:19:17 +08:00
你有两个结构体,一个是程序,叫 program ,另一个是人,叫 human ,他们都有个方法,.Run()

有个接口叫 Runner ,他定义了一个方法叫做 .Run(),所以 program 和 human 都实现了这个接口

现在有个函数叫做 代码太烂怎么办,WhatIfTheCodeBad(runner Runner),参数是 接口 Runner ,你传 program 和 human 都可以,因为他们都能跑 (实现了 Runner 接口)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/846241

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX