【Go实战基础】多态是怎么实现的

本文深入讲解Go语言中的接口概念,包括基本概念、数据结构及其实现原理,并通过实例演示如何定义和使用接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、基本概念

二、数据结构

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 {
	size       uintptr // 占用内存大小
	ptrdata    uintptr // 包含所有指针的内存前缀大小
	hash       uint32  // 类型 hash
	tflag      tflag   // 标记位,用于反射
	align      uint8   // 对齐字节信息
	fieldAlign uint8   // 对齐字节数
	kind       uint8   // 基础类型枚举值
	equal func(unsafe.Pointer, unsafe.Pointer) bool // 比较对应对象的类型是否相等
	gcdata    *byte    // GC 类型的数据
	str       nameOff  // 类型名称字符串偏移量
	ptrToThis typeOff  // 类型元信息指针偏移量
}

3、空 interface 数据结构

空的 inferface{} 是没有方法集的接口,所以不需要 itab 数据结构,只需要存类型和类型对应的值即可。对应的数据结构如下:

// 空接口定义
// 只有当 2 个字段都为 nil,空接口才为 nil
type eface struct {
	_type *_type
	data  unsafe.Pointer
}

空的 interface 没有方法,所以可以认为所有的类型都实现了 interface{}。
如果定义一个函数参数是 interface{} 类型,这个函数应该可以接受任何类型作为它的参数。

三、菜鸟实战

实战需求:定义并实现接口

马上安排!

1、创建 g006.go

/*
 * @Author: 菜鸟实战
 * @FilePath: /go110/go-006/g006.go
 * @Description: 接口
 */

package main

import (
	"fmt"
	"runtime"
)

// 定义结构体
type Student struct {
	Name string
}

// 空接口
func test_nil_interface() {
	var v interface{}
	v = 123
	v = "abcd"
	v = 10.2

	v = 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 
 

菜鸟实战,持续学习!

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟实战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值