请教各位 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 ,往大家多多解惑
3988 次点击
所在节点    Go 编程语言
31 条回复
johopig
2022-04-11 12:05:51 +08:00
假如其他地方要使用到 run ,那只要参数定义为 C ,就可以根据实际情况使用 A 或 B 而不用修改参数了
dzdh
2022-04-11 12:21:17 +08:00
type DoI interface { func run() }

type DoSome struct { func run() {} }

func ToDO(obj DoI) {}

ToDO(&DoSome{})
dzdh
2022-04-11 12:21:38 +08:00
想想适配器的设计模式
zhangfeiwudi
2022-04-11 12:27:03 +08:00
多态啊,唐老鸭,北京烤鸭,可达鸭,白马会所头牌鸭 都是鸭子。但是细分不同,所以需要通过接口统一规范,屏蔽掉底层实现逻辑的不同,统一使用一致的方法。

再比如说 io 接口就是非常的好解释。 只要能实现 read write 都可以作为 io 参数传递,所以 网络是 io, 文件也是 io, 内存也是 io 。 其实这是面向对象的一些知识点,如果做过 java 或者 php 就会对这一块比较了解了
seers
2022-04-11 12:29:44 +08:00
我也刚看到这个,一样的疑惑,不过我觉得可能是一种约束,如果能实现这个接口就必定能用接口的方法,一个高层一点的抽象
Elaina
2022-04-11 12:45:52 +08:00
这个还是为了多态,最简单的一个例子,假设你有一个动物基类,拥有一个 run 方法,然后派生出了 n 个动物类(比如猫、狗、猴子等等),然后有一个函数,函数需要传入一个动物类,并在函数体内调用对应的 run 方法。这个时候,如果你不使用接口,则需要为每一个动物类都定义一个这样的方法,会产生大量冗余代码。
yunshangdetianya
2022-04-11 13:37:31 +08:00
谢谢各位的指导,我也再去想想,只是感觉接口存在是为了管理方法而存在,在实际应用时候,还没搞懂到底在那些场景下使用
dongtingyue
2022-04-11 14:07:17 +08:00
实际使用中的例子,win 和 linux 下读取文件列表可以抽象一个 list()方法,在不同地方使用的时候不需要判断是 a.list 还是 b.list 直接 x.list 至于判断在封装的时候处理一次就行。
如果是简单的情况可以像你那样直接弄,确实没必要再封一层。
yunshangdetianya
2022-04-11 14:10:16 +08:00
@dongtingyue 谢谢,我去体会下,可能使用的少,不是很明白
BeautifulSoap
2022-04-11 14:15:59 +08:00
lz 你学 go 之前是一直在用动态类型语言吗( JS ,Python 之类的),如果是习惯了动态语言的,的确一开始即非常难以理解接口的用处的
lostpg
2022-04-11 14:23:03 +08:00
接口的存在使得调用 run 的的上下文中不需要确切知道被调用者的具体类型,只需要知道被调用者满足接口约定,就可以使用接口所定义的行为。
yunshangdetianya
2022-04-11 14:25:21 +08:00
@BeautifulSoap 是的,使用 python 的,所以才觉得疑惑
yunshangdetianya
2022-04-11 14:26:53 +08:00
@lostpg 感觉接口像是类的实例化,但又不完全是,不知道我理解的对不对
yunshangdetianya
2022-04-11 14:27:36 +08:00
@BeautifulSoap 有什么可以帮助理解的方法或者代码例子吗?
lostpg
2022-04-11 14:41:10 +08:00
@yunshangdetianya #13

> 感觉接口像是类的实例化

说得不对,接口是 OOP 相关的概念,你可能需要相关的前置知识。
yunshangdetianya
2022-04-11 14:48:27 +08:00
@lostpg 需要补一补那块知识,我去学习下
soupu626
2022-04-11 15:32:21 +08:00
@yunshangdetianya 这个其实不是 go 的问题,是 OOP 的概念,可以看看 设计模式
我理解接口最大的用处是解耦,面向接口编程,而不关心具体实现

比如有个任务系统 TaskService ,在某些条件下需要发消息,然后 PushSerivce 给出了一个接口 push(param),提供了消息推送的能力
这样 TaskSerivce 就只需要关心内部的逻辑,至于推送,不用关心细节,只要知道有个 push 接口,直接调就行。
而对于 PushSerivce ,他只提供了一个标准接口,只要保证接口功能和定义正常,底层实现可以随意更换,比如换运营商,换推送渠道(短信、APP ),或者根据入参,路由到不同的实现类上(策略模式)
这里的 PushService 就是你说的 C ,针对不同运营商、渠道的实现就是 A 和 B
BeautifulSoap
2022-04-11 15:43:08 +08:00
@yunshangdetianya 直接在这里讲好了

很正常的,编程先接触动态语言的话就会很难理解静态语言的接口到底有什么意义,ls 很多人说的其实都对,但都是站在静态语言使用者的角度在教你,你作为一个动态语言接触编程的人是没法轻松理解他们到底在说什么的。因为接口提供的动态能力是动态语言天生就有的,最先接触动态语言的话会把这种动态能力当成呼吸一样理所当然,所以没法理解静态语言这么大费周章是图什么

所以要跟你讲清楚接口,那就要从 python 角度来帮你理解 —— 在 python 中(虽然 python 没接口),接口就相当于在你调用对象的方法时加了一道验证,限制了过于自由类型系统

比如很下面这段 Python 代码是可以直接跑的,但显然会执行出错对不对,因为 123 和 "Hello" 并没有实现 run()方法

```main.py
# 假设 A 和 B 是 class 并实现了 run() 方法
l = [ A(), B(), 123, "Hello" ]

for v in l:
v.run()

```
上面这问题虽然看起来一目了然,但在复杂的代码中是非常容易出现的(代码复杂了你没法保证会不会脑子抽了随便塞个奇怪的变量到上面的 list 里)

那好,你一定就会想,有没有一套聪明办法,让我能限制 l 这个列表只能放实现了 `.run()` 方法的变量?比如像下面这样的伪代码,我自创了一个方法集 RunRunRun:

```
# 定义一个方法集合
method_set RunRunRun:
run()


l[ RunRunRun ] = [ A(), B(), 123, "Hello" ]

# 我这里随便自创了一种写法,指定了列表 l 只能存放实现了方法集 RunRunRun 的变量
# 因为 123 和 "Hello" 没有实现方法集 RunRunRun 里的所有方法,所以这行代码在编写阶段就可以被 IDE 检测出来,并且在编译阶段直接就能报错。而用不着每次到代码跑起来崩了才注意到
```

在上面段伪代码中,方法集(method_set)的另一个通用的叫法就是接口(interface)。这就是接口的用处。这就是站在动态语言角度来理解接口,接口实际上就是在限制动态语言里过于自由的类型赋值。之所以上面很多人说得你不太理解,其实是站在静态语言角度在给你讲。如果你还不太理解的话,就像上面这样理解接口就行了。
droppedbytech
2022-04-11 16:14:51 +08:00
我有点异端,我不认为 Go 的接口是 OOP 的设计。Go 的接口在我看来和其他 OOP 语言的最大区别是,你不需要声明你“实现”了一个接口,只要这个类有这个方法,它就是这个接口。这种方式我认为这是更“自然”,更符合软件开发特点的,用 Rob Pike (Go 创始人之一)的用语就是 organically 。你可以去看看 fmt.Fprintf 的使用就是一个典型例子,当你自己的类实现了一个 io.Writer 的接口,你就自然而然地可以使用这个方法,而整个过程你甚至不需要显式 import io 这个包。
BrightSphere
2022-04-11 16:18:15 +08:00
这样就可以把依赖的 A 或者 B 替换成实现了接口 C 的 D 来进行单元测试了

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

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

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

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

© 2021 V2EX