【Go实战基础】多态是怎么实现的
目录
一、基本概念
二、数据结构
1、interface 定义接口
2、非空 interface 数据结构
3、空 interface 数据结构
三、菜鸟实战
1、创建 g006.go
2、编译和运行
3、运行结果
一、基本概念
面向对象编程(OOP)中三个基本特征分别是封装,继承,多态。在 Go 语言中封装和继承是通过 struct 来实现的,而多态则是通过接口(interface)来实现的。
Interface 是 Go 语言的基础特性之一,可以理解为一种类型的规范或者约定。 在 Go 中,接口是一组方法签名。当类型为接口中的所有方法提供定义时,它被称为实现接口。
当我们给系统添加一个功能的时候,不是通过修改代码,而是通过增添代码来完成,那么就是开闭原则的核心思想了。要想满足这种要求,就需要interface来提供一层抽象的接口,从而实现高内聚,低耦合。
二、数据结构
1、interface 定义接口
使用关键字 interface 用来定义接口,语法如下:
// 定义一个接口type interface_name interface { method_name1([args ...arg_type]) [return_type] method_name2([args ...arg_type]) [return_type] method_name3([args ...arg_type]) [return_type] ... method_namen([args ...arg_type]) [return_type]}
2、非空 interface 数据结构
非空的 interface 初始化的底层数据结构是 iface
// 非空 interface 数据结构type iface struct { // 存放类型、方法等信息,是 itab 类型的指针tab *itab // 指向的 iface 绑定对象的原始数据的副本data unsafe.Pointer}// itab 指针数据结构type itab struct { // 存 interface 自己的静态类型inter *interfacetype // 类型元信息,存 interface 对应具体对象的类型_type *_type // hash 字段hash uint32 _ [4]byte // 函数指针,它指向的是具体类型的函数方法 // 在这个指针对应内存地址的后面依次存储了多个方法,利用指针偏移便可以找到它们fun [1]uintptr }
Go 语言在编译时会对每个变量的类型信息做强校验,所以每个类型的元信息要用一个结构体描述,_type 就是所有类型最原始的元信息。
// 类型元信息type _type struct {sizeuintptr // 占用内存大小ptrdata uintptr // 包含所有指针的内存前缀大小hashuint32 // 类型 hashtflag tflag // 标记位,用于反射align uint8 // 对齐字节信息fieldAlign uint8 // 对齐字节数kinduint8 // 基础类型枚举值equal func(unsafe.Pointer, unsafe.Pointer) bool // 比较对应对象的类型是否相等gcdata *byte // GC 类型的数据strnameOff // 类型名称字符串偏移量ptrToThis typeOff // 类型元信息指针偏移量}
3、空 interface 数据结构
空的 inferface{} 是没有方法集的接口,所以不需要 itab 数据结构,只需要存类型和类型对应的值即可。对应的数据结构如下:
// 空接口定义// 只有当 2 个字段都为 nil,空接口才为 niltype eface struct {_type *_typedata unsafe.Pointer}
空的 interface 没有方法,所以可以认为所有的类型都实现了 interface{}。
如果定义一个函数参数是 interface{} 类型,这个函数应该可以接受任何类型作为它的参数。
三、菜鸟实战
实战需求:定义并实现接口
马上安排!
1、创建 g006.go
/* * @Author: 菜鸟实战 * @FilePath: /go110/go-006/g006.go * @Description: 接口 */package mainimport ("fmt""runtime")// 定义结构体type Student struct {Name string}// 空接口func test_nil_interface() {var v interface{}v = 123v = "abcd"v = 10.2v = Student{Name: "Tom"} // 自定义结构体类型//判断v的类型if _, ok := v.(int); ok {fmt.Printf(" 是int类型 \n")} else if _, ok := v.(string); ok {fmt.Printf(" 是字符串类型\n")} else if _, ok := v.(Student); ok {fmt.Printf(" 是自定义结构体类型\n")} else {fmt.Printf("未知类型\n")}}// 定义接口type Phone interface {call()sendMessage()}// 声明结构体, 实现接口type Huawei struct {name string}// Huawei 实现接口func (huawei Huawei) call() {fmt.Printf("%s 有打电话功能...\n", huawei.name)}func (huawei Huawei) sendMessage() {fmt.Printf("%s 有发短信功能...\n", huawei.name)}func test_interface() {// 华为mate := Huawei{name: "Mate",}mate.call()mate.sendMessage()}func main() {// 使用内置函数打印println("Hello", "菜鸟实战")// 测试 空接口test_nil_interface()// 测试 非空接口test_interface()// 使用包函数打印fmt.Printf("版本: %s \n", runtime.Version())}
2、编译和运行
# 1、生成模块依赖
go mod init g006
# 2、编译
go build g006.go
# 3、编译后的目录结构
└── go-006
├── g006
├── g006.go
└── go.mod
# 4、运行
go run g006
3、运行结果
Hello 菜鸟实战
是自定义结构体类型
Mate 有打电话功能...
Mate 有发短信功能...
版本: go1.17.10
菜鸟实战,持续学习!