Tony Bai · Go 语言第一课
Tony Bai
资深架构师,tonybai.com 博主
21492 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 59 讲
开篇词 (1讲)
结束语 (1讲)
Tony Bai · Go 语言第一课
15
15
1.0x
00:00/00:00
登录|注册

30|接口:Go中最强大的魔法

实现HTTP请求处理的链式调用
结合包装器和适配器模式
将普通函数转换为接口实现
适配器函数类型
返回具备新功能特性的类型
对输入参数类型的包装
实例化结构体
接受接口,返回结构体
使用接受接口类型参数的函数或方法
实现灵活性和扩展性
连接不同类型
接口作为“关节”
接口定义重用
方法复用
类型嵌入
其他接口应用模式的探索和分享
Go泛型可能替代部分空接口使用场景
空接口不提供类型安全保护
避免使用空接口作为函数参数
中间件模式
适配器模式
包装器模式
创建模式
基本模式
水平组合
垂直组合
接口与实现者无显式关联
方法与类型正交
类型无层次结构
正交性
一切皆组合
接口解耦与抽象成本
避免过度设计
在真正需要时才抽象
接口的抽象作用
接口的运行时表示
接口定义
思考题
注意事项
接口应用模式
组合方式
Go的设计哲学
接口的使用原则
接口的基本概念
Go语言接口应用模式

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

你好,我是 Tony Bai。
在前面的两讲中,我们学习了接口的基础知识、接口类型定义的惯例以及接口在运行时的表示。掌握了这些内容后,可以说,在语法层面的有关接口的问题,对我们来说都不是什么阻碍了。在弄清楚接口是什么这个问题之后,摆在我们面前的就是怎么用接口的问题了。
不过,这里的“怎么用”,可不是要告诉你怎么使用 Go 标准库中的接口或第三方包中定义好的接口,而是让你学习如何利用接口进行应用的设计,以及改善已有应用的设计,换句话说就是 Go 接口的应用模式或惯例
不过在讲解接口应用模式之前,我们还先要了解一个前置原则,那就是在实际真正需要的时候才对程序进行抽象。再通俗一些来讲,就是不要为了抽象而抽象。上一讲中我们说过,接口本质上是一种抽象,它的功能是解耦,所以这条原则也在告诉我们:不要为了使用接口而使用接口。举一个简单的例子,如果我们要给一个计算器添加一个整数加法的功能特性,本来一个函数就可以实现:
func Add(a int64, b int64) int64 {
return a+b
}
但如果你非要引入一个接口,结果代码可能就变成了这样:
type Adder interface {
Add(int64, int64) int64
}
func Add(adder Adder, a int64, b int64) int64 {
return adder.Add(a, b)
}
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Go语言中的接口是一种强大的特性,通过组合的方式实现了高内聚和低耦合的设计。文章介绍了Go语言的组合设计哲学,强调了正交性的重要性,以及Go语言提供的正交语法元素。接口在Go程序的静态结构搭建与耦合设计中扮演着至关重要的角色。文章还详细介绍了垂直组合和水平组合两种主要的组合方式,以及它们的含义与应用范围。此外,文章还介绍了包装器模式、适配器模式和中间件模式的应用,展示了接口在程序设计中的重要作用。最后,文章强调了尽量避免使用空接口作为函数参数类型,提出了关于接口使用的注意事项。整体而言,本文深入浅出地介绍了Go语言中接口的强大特性和灵活应用,对于想要深入了解Go语言接口设计的读者来说,是一篇极具价值的文章。文章内容涵盖了接口的应用模式,强调了使用接口的原因和与Go语言“组合”设计哲学的关联。垂直组合和水平组合作为主要的组合方式得到了详细阐述,同时还介绍了包装器模式、适配器模式和中间件模式的应用。最后,强调了避免使用空接口作为函数参数类型。整体而言,本文对于深入理解Go语言接口设计具有重要意义。

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

全部留言(30)

  • 最新
  • 精选
  • return
    老师讲的太好了,虽然定位是入门, 但个人认为, 基础才是最核心的, 老师把基础讲的太透彻了。这个专栏比某些进阶高阶专栏好多了。 这一篇 加深了 我对组合的理解, 感谢老师用心的输出。 好饭不怕晚, 耐心等等老师后续的 高质量知识, 大家别催,品质第一。

    作者回复: 👍

    2021-12-31
    31
  • Geek_2337af
    在学习上遇到一个问题,请老师解答: IntSet类型的String方法的接收者是一个指针类型,所以我们不能在一个不能寻址的IntSet值上调用这个方法 type IntSet struct { /* ... */ } func (*IntSet) String() string var _ = IntSet{}.String() // compile error: String requires *IntSet receiver 但是我们可以在一个IntSet值上调用这个方法: var s IntSet var _ = s.String() // OK: s is a variable and &s has a String method 1.怎么理解这个不能寻址的IntSet值 2.调用方法的习惯是直接使用结构体变量(var i InSet),还是j := InSet{},假设方法中不需要使用到这个实例

    作者回复: 好问题!👍 1. go规范中说: 只有可寻址的(addressable)的变量在调用*T作为receiver参数类型的方法时,Go才会施展“语法糖”,取其地址再调用对应的方法。关于addressable这个概念比较复杂,在专栏里不便展开,就没有提。var _ = IntSet{}.String() 中的IntSet()是一个中间值,是不可获得其地址的,因此不能被自动转换,因此编译器报错。 2. 调用方法的习惯没有标准😁

    2022-02-18
    2
    11
  • aoe
    Go 中的接口实现的是真里氏替换原则(LSP),再也不用担心父类强转子类后使用子类特有方法的假里氏替换原则了

    作者回复: 👍

    2022-01-03
    7
    8
  • 文经
    白老师,这段代码我有点疑问: type HandlerFunc func(ResponseWriter, *Request) 这里是定义了HandlerFunc类型 http.HandlerFunc(greetings) 在这里是不是对greetings做了类型转换?像是int64(123)。我把这个跟对象的初始化有点混淆,觉得要有个字段来存储greetings的值。

    作者回复: 你的理解没错!这个在专栏前面的课程中也讲过,这里就是一个类型转换。通过类型转换,HandlerFunc可以让一个普通函数成为实现ServeHTTP方法的对象,从而满足http.Handler接口。

    2022-01-16
    2
    7
  • SuperSu
    先生循循善诱,看的学生直呼过瘾

    作者回复: 👍

    2022-08-04归属地:辽宁
    2
    4
  • 多选参数
    特别喜欢白老师讲 Go,这个专栏虽然说是 Go 第一课,但是感觉这内容已经不是基础的内容,而是作为深度入门 Go 的课了。另外,整篇专栏中,老师始终在不断给我讲 Go 的思想,这点真的超 nice。原本我觉得用一门要用它特有的东西,比如 Go 的并发,而白老师让我更深入去理解 Go 的思想,这才是活用一门语言的样子。

    作者回复: 👍

    2022-01-25
    4
  • Calvin
    Gopher 这里说的“中间件”和 PHPer 的“中间件”概念是不是有点像? 但是貌似跟 Javaer 的“中间件”概念不太一样:Javaer 的“中间件”是类似 kafka、zookeeper 等之类的软件项目,而 Gopher 的“中间件”感觉更像是 Javaer 中的“过滤器”、“拦截器”概念?

    作者回复: 你说的没错。中间件(middleware)这个词的具体含义要结合具体上下文来看。

    2022-01-05
    4
  • 撕影
    犹如看精彩进球集锦,天知道老师在之前倒了多少脚,流了多少汗

    作者回复: 👍

    2022-11-25归属地:辽宁
    3
  • 文经
    强烈请求白老师做一次加餐:讲一讲自己的Go语言学习之路,以及自己怎么做到写出来的文章即通俗易懂又足够深入的👍这种能力能学习不?

    作者回复: 我自己的学习之路,我还真没有“认真”总结过。手动允悲:)。

    2022-01-16
    3
  • Geek_73c432
    type MyError struct { err error } func (e MyError) Error() string { return "fatal error" } func NewError(e error) *MyError { var p *MyError p = &MyError{err: e} return p } 在创建者模式中,我看到创建函数的惯例是返回结构的指针,例如变量 p,但是函数调用后变量 p 所在的栈帧已经被回收了啊,那外部的指针 q := NewError(e) 指向的地址不是无效了么?

    作者回复: Go编译器会对各个变量做逃逸分析(escape analysis),对于逃逸的变量,go编译器会将其分配在heap上,这样return 的p在函数NewError外面使用也是安全有效的。

    2023-05-13归属地:广东
    2
收起评论
显示
设置
留言
30
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部