Go 语言核心 36 讲
郝林
《Go 并发编程实战》作者,前轻松筹大数据负责人
79610 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 55 讲
Go 语言核心 36 讲
15
15
1.0x
00:00/00:00
登录|注册

14 | 接口类型的合理运用

调用接口方法的注意事项
善用接口组合和小接口
接口组合的优势
接口的组合方式
实现类型的nil值赋给接口变量
接口变量的值在何种情况下为nil
接口变量的动态值、动态类型和静态类型
接口变量的字段值
赋值时的动态类型和动态值
动态值、动态类型和静态类型的含义
无侵入式的接口实现方式
通过方法集合判断实现类型
判断方法实现的条件
无侵入式的接口实现方式
方法集合代表接口的全部特征
接口类型的类型字面量与结构体类型的区别
通过关键字typeinterface声明接口类型
值为nil的实现类型的变量赋给接口变量
接口之间的组合
接口变量的值为nil
接口变量的赋值
接口类型的变量
接口的实现类型
接口的方法集合
接口类型的声明
思考题
怎样用好Go语言的接口
正确使用接口的基础知识
接口类型的合理运用

该思维导图由 AI 生成,仅供参考

你好,我是郝林,今天我们来聊聊接口的相关内容。

前导内容:正确使用接口的基础知识

在 Go 语言的语境中,当我们在谈论“接口”的时候,一定指的是接口类型。因为接口类型与其他数据类型不同,它是没法被实例化的。
更具体地说,我们既不能通过调用new函数或make函数创建出一个接口类型的值,也无法用字面量来表示一个接口类型的值。
对于某一个接口类型来说,如果没有任何数据类型可以作为它的实现,那么该接口的值就不可能存在。
我已经在前面展示过,通过关键字typeinterface,我们可以声明出接口类型。
接口类型的类型字面量与结构体类型的看起来有些相似,它们都用花括号包裹一些核心信息。只不过,结构体类型包裹的是它的字段声明,而接口类型包裹的是它的方法定义。
这里你要注意的是:接口类型声明中的这些方法所代表的就是该接口的方法集合。一个接口的方法集合就是它的全部特征。
对于任何数据类型,只要它的方法集合中完全包含了一个接口的全部特征(即全部的方法),那么它就一定是这个接口的实现类型。比如下面这样:
type Pet interface {
SetName(name string)
Name() string
Category() string
}
我声明了一个接口类型Pet,它包含了 3 个方法定义,方法名称分别为SetNameNameCategory。这 3 个方法共同组成了接口类型Pet的方法集合。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了Go语言中接口类型的特性和运用。接口类型通过方法定义来构成方法集合,只要一个数据类型的方法集合中完全包含了一个接口的全部特征,那么它就是这个接口的实现类型。文章通过示例代码展示了接口变量的赋值和方法调用,引出了对于接口变量赋值后字段值的预期结果。此外,文章还详细解释了接口变量的动态值、动态类型和静态类型的概念,以及接口变量赋值时存储的数据结构。读者通过本文可以快速了解接口类型的特点和在Go语言中的合理运用。文章还介绍了接口之间的组合,强调了使用小接口和接口组合可以增加程序的灵活性和稳定性。文章最后提出了一个思考题,引发读者对接口方法调用的注意事项进行思考。通过本文,读者可以全面了解Go语言中接口类型的特性和运用,以及如何合理地使用接口组合来构建灵活的程序框架。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Go 语言核心 36 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(83)

  • 最新
  • 精选
  • hiyanxu
    置顶
    老师,您好: 我在这篇文章中看到您说,给接口类型变量赋值时传递的都是副本,我测试了,确实是不会改变被赋值后的接口类型变量。 后面,我重新给Pet接口加上了SetName()方法,然后让*Dog类型实现了该Pet接口,然后声明并初始化了一个d,将d的地址&d赋值给Pet类型的接口变量: d := Dog{name: "little dog"} var pet Pet = &d 此时,我去修改了d的name字段: d.SetName("big dog") 运行后发现输出不仅d的name字段变为了“big dog”,同样pet接口变量也变成了“big dog”。 在此时我是不是可以说,传递给pet变量的同样是&d的一个指针副本,因为传递的是副本,所以无论是指针还是值,都可以说是浅复制;且由于传递的是指针(虽然是副本),但还是会对指向的底层变量做修改。 请问老师,我上面的推断是正确的吗? 另外我想说真的每篇文章都需要好好研读啊,看一篇得两个小时,里面好多干货,谢谢老师!

    作者回复: 没错,虽然是副本,但却是指针的副本,SetName又是指针方法。所以综合起来这种修改就生效了。 另外这类副本都是浅表复制。也没错。

    2018-12-19
    2
    31
  • 志鑫
    思考题,要看实现类型是值类型还是指针类型; var d2 Dog var p2 Pet = d2 if p2 != nil { fmt.Println("p2.Name()", p2.Name()) } var d3 *Dog var p3 Pet = d3 if p3 != nil { fmt.Println("p3.Name()", p3.Name()) //运行是报错,panic: value method main.Dog.Name called using nil *Dog pointer }

    作者回复: 这主要是因为 Dog 和 *Dog 的零值是完全不同的,前者是 Dog{} ,而后者是 nil 。

    2019-05-10
    35
  • 俊杰
    老师您好,有个地方不理解,对象赋值给接口后,为什么判等操作返回的是true呢?比如上面的例子:pet = dog之后紧接着判断pet == dog,返回的是true,按上面的说法,赋值后不是应该被包装成了一个iface吗?这里的判等操作到底是依据什么来判断的呢?麻烦老师解释一下,谢谢~

    作者回复: 你可以参照Go语言规范中的说明:https://golang.google.cn/ref/spec#Comparison_operators,请注意下面这句: A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t's dynamic type is identical to X and t's dynamic value is equal to x.

    2019-03-20
    4
    13
  • 吉他
    关于思考题,如果我们把一个值为nil的某个实现类型的变量赋给了接口变量,那么在这个接口变量上仍然可以调用该接口的方法吗? 可以的,不过方法内不能使用实现类型内的变量,并且方法接收者必须是指针类型

    作者回复: 对的,对于指针方法来说是这样。

    2019-05-25
    3
    12
  • lesserror
    郝林老师,这个专栏过去快三年了,里面的很多内容都对我受益很大。 但是好像没了老师的动态了,不知道郝林老师这几年都在从事什么类型的工作呢?

    作者回复: 很高兴,谢谢关注哈:) 我还是依然在当“坐家”,依然没有全职工作。 (下面也算是我给自己的记录吧) 2019年,我出了一本新书《Julia编程基础》。Julia语言也是一门通用编程语言,不过更倾向于科学计算和数据科学。它的官方文档对初学者不友好,所以我就填补了一下空白,写了一本给小白看的Julia编程书。 2010年,我换了住址,也一直在找方向,做了一些尝试。但由于自身的执行力受限,这些尝试都没怎么出成果。年底的时候,我帮某个技术培训机构制定了一整套Go语言培训体系。 2021年,春节过后的一段时间,我为某大厂审核了Go语言编程规范。在这之后,我一直在规划和撰写一个新的教程,关于软件概要设计的。要是你有兴趣的话,可以关注我的微信公众号“迭代码”。我觉得如果能够写一本跟编程语言无关的软件设计书的话,应该可以帮助更多的人。:) 说到编程语言,我现在除了Go语言,还在重点关注Julia语言和Rust语言。我把Julia作为个人的数据挖掘语言,把Rust作为一种理解新编程技术和底层系统的帮手。 最后,其实我也挺想全职工作的,可惜条件还暂时不允许。不过,持续做一些我认为有意义的事,也算是一种积极的生活吧。

    2021-07-31
    4
    10
  • 张硕
    _, ok := interface{}(dog).(Pet) 这个表达式是什么意思啊?

    作者回复: 判断 dog 变量的值是不是 Pet 类型的,判断结果存于 ok 变量。

    2020-03-31
    2
    6
  • Chaos
    demo32.go line:32 var pet Pet = dog 是不是应该 var pet Pet = &dog 附:https://github.com/hyper0x/Golang_Puzzlers/blob/master/src/puzzlers/article14/q1/demo32.go

    作者回复: 这是在示范“在原来的基本值上调用指针方法并修改其内部字段值”,然后展示“这样并不会改变接口值”。这是一个反例。需要大家运行之后思考的。 你有这样的思考,很好:)

    2020-01-09
    5
  • 兔子高
    你好,请问分别在什么情况下使用值方法和什么情况下使用引用方法呢

    作者回复: 需要改动值内部数据的时候必须使用指针方法。其他时候就要看接口实现、被嵌入要求等方面了。我觉得一般情况下用指针方法就好了。

    2018-09-12
    5
  • saltedfish
    这有两个充分必要条件,一个是“两个方法的签名需要完全一致”,另一个是“两个方法的名称要一模一样”。显然,这比判断一个函数是否实现了某个函数类型要更加严格一些。 对于这里我有两个疑问: 1. 方法签名不就包括方法的名字吗? 2. 函数实现某个函数类型是什么意思?

    作者回复: 1. 方法签名除了名字还有参数列表和结果列表啊。 2. 下面这行代码是在定义一个函数类型: type Check func(s string) bool 而下面这行代码是在定义一个函数(实现): func CheckLen(content string) bool { if len(content) >= 3 { return true } return false } 现在,我们可以说“函数 CheckLen 是函数类型 Check 的一个实例”。

    2020-07-05
    4
  • Crush
    所有值为nil的变量a只要不是接口变量,a == nil是不是就成立?

    作者回复: 更精确的说法是:除了接口类型以外的所有引用类型的值,只要它的实际值为nil,自然就等于nil。 多解释两句:对于这些类型,它们的值就是实际值。而接口类型的值与它们不同,会在实际值之外再包一层,正如文中所述。

    2020-01-14
    3
收起评论
显示
设置
留言
83
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部