interface理解
interface(接口)是golang最重要的特性之一,实现多态。Interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。
特点
- interface 是方法或行为声明的集合
- interface接口方式实现比较隐性,任何类型的对象实现interface所包含的全部方法,则表明该类型实现了该接口。
- interface还可以作为一中通用的类型,其他类型变量可以给interface声明的变量赋值。
- interface 可以作为一种数据类型,实现了该接口的任何对象都可以给对应的接口类型变量赋值。
底层实现
Go的interface源码在Golang源码的runtime目录中。
Go的interface是由两种类型来实现的:iface和eface。
两种接口
runtime.iface
package main import "fmt" // Person 定义接口 type Person interface { GetName() string GetAge() uint32 } // Student 定义类型 type Student struct { Name string Age uint32 } func (s Student) GetName() string{ return s.Name } func (s Student) GetAge() uint32{ return s.Age } func main() { var student Student student.Age = 12 student.Name = "小明" var person Person person = student //接口执行向student fmt.Printf("name:%s,age: %d\n", person.GetName(), person.GetAge()) }
内部结构
type iface struct { tab *itab data unsafe.Pointer }
itab源码
type itab struct { inter *interfacetype //此属性用于定位到具体interface _type *_type //此属性用于定位到具type hash uint32 // copy of _type.hash. Used for type switches. _ [4]byte fun [1]uintptr //方法集 }
代码例子
package main import "fmt" // Person 定义接口 type Person interface { GetName() string GetAge() uint32 } // Student 定义类型 type Student struct { Name string Age uint32 } func (s Student) GetName() string{ return s.Name } func (s Student) GetAge() uint32{ return s.Age } func main() { var student Student student.Age = 12 student.Name = "小明" var person Person person = student fmt.Printf("name:%s,age: %d\n", person.GetName(), person.GetAge()) }
runtime.eface
使用runtime.eface表示第二种不包含任何方法的接口,第二种在我们日常开发中经常使用到,所以在实现时使用了特殊的类型。从编译角度来看,golang并不支持泛型编程。但还是可以用interface{} 来替换参数,而实现泛型。
空接口interface{}没有任何方法,所以所有类型都实现了空接口,即我们可以把任何一个变量赋给空接口类型。
var person interface{} = xxxx实体
侵入式与非侵入式的理解
侵入式
你的代码里已经嵌入了别的代码,这些代码可能是你引入过的框架,也可能是你通过接口继承得来的,比如:java中的继承,必须显示的表明我要继承那个接口,这样你就可以拥有侵入代码的一些功能。所以我们就称这段代码是侵入式代码。
优点:通过侵入代码与你的代码结合可以更好的利用侵入代码提供给的功能。
缺点:框架外代码就不能使用了,不利于代码复用。依赖太多重构代码太痛苦了。
非侵入式
正好与侵入式相反,你的代码没有引入别的包或框架,完完全全是自主开发。比如go中的接口,不需要显示的继承接口,只需要实现接口的所有方法就叫实现了该接口,即便该接口删掉了,也不会影响我,所有go语言的接口数非侵入式接口;再如Python所崇尚的鸭子类型。
优点:代码可复用,方便移植。非侵入式也体现了代码的设计原则:高内聚,低耦合。
缺点:无法复用框架提供的代码和功能。
java实现
public interface IPersonService { String getName(); Integer getAge(); }
public class PersonService implements IPersonService{ @Override public String getName() { return "小明"; } @Override public Integer getAge() { return 12; } }
go实现
package main import "fmt" // Person 定义接口 type Person interface { GetName() string GetAge() uint32 } // Student 定义类型 type Student struct { Name string Age uint32 } func (s Student) GetName() string{ return s.Name } func (s Student) GetAge() uint32{ return s.Age } func main() { var student Student student.Age = 12 student.Name = "小明" var person Person person = student fmt.Printf("name:%s,age: %d\n", person.GetName(), person.GetAge()) }
区别
侵入式通过 implements 把实现类与具体接口绑定起来了,因此有了强耦合;
假如修改了接口方法,则实现类方法必须改动;
假如类想再实现一个接口,实现类也必须进行改动;
后续实现此接口的类,必须了解相关的接口;
Go语言非侵入式的方式很好地解决了这几个问题,只要实现了实现了与接口相同的方法,就实现了这个接口。随着代码量的增加,根本不需要的关心实现了哪些接口,不需要刻意去先定义接口再实现接口的固定模式,在原有类新增实现接口时,不需要更改类,做到低侵入式、低耦合开发的好处。
interface应用
类型转换
ok-idiom模式
type data int func(d data)String()string{ return fmt.Sprintf("data:%d",d) } func main() { var d data=15 var x interface{} =d if n,ok:=x.(fmt.Stringer);ok{ // 转换为更具体的接口类型 fmt.Println(n) } if d2,ok:=x.(data);ok{ // 转换回原始类型 fmt.Println(d2) } e:=x.(error) // 错误:main.data is not error fmt.Println(e) }
siwch模式
func main() { var x interface{} =func(x int)string{ return fmt.Sprintf("d:%d",x) } switch v:=x.(type) { // 局部变量v是类型转换后的结果 case nil: println("nil") case*int: println(*v) case func(int)string: println(v(100)) case fmt.Stringer: fmt.Println(v) default: println("unknown") } }
多态
......
参考
来源:
https://blog.51cto.com/u_14523732/5639864
https://blog.csdn.net/yuqiang870/article/details/124746693
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!