【Go语言】接口类型(一)接口类型与接口的值

本文是介绍golang接口类型的第一篇,主要介绍接口类型与接口类型的值的相关概念。

1. 静态类型、动态类型、动态值

所谓的静态类型(即 static type),就是变量声明的时候的类型。

go 复制代码
var age int   // int 是静态类型
var name string  // string 也是静态类型

它是你在编码时,肉眼可见的类型。

所谓的 动态类型 (即 concrete type,也叫具体类型)是 程序运行时系统才能看见的类型。

这是什么意思呢?

我们都知道 空接口 可以承接什么问题类型的值,什么 int 呀,string 呀,都可以接收。

比如下面这几行代码

go 复制代码
var i interface{}   
i = 18  
i = "Go编程"

第一行:我们在给 i 声明了 interface{} 类型,所以 i 的静态类型就是 interface{}

第二行:当我们给变量 i 赋一个 int 类型的值时,它的静态类型还是 interface{},这是不会变的,但是它的动态类型此时变成了 int 类型。

第三行:当我们给变量 i 赋一个 string 类型的值时,它的静态类型还是 interface{},它还是不会变,但是它的动态类型此时又变成了 string 类型。

从以上,可以知道,不管是 i=18 ,还是 i="Go编程",都是当程序运行到这里时,变量的类型,才发生了改变,这就是我们最开始所说的动态类型是程序运行时系统才能看见的类型

2. 接口类型的值

由于接口类型的值可以是任意一个实现该接口的类型值,所以除了具体的值,接口值还需要记录这个值的类型。也就是说接口值由类型(type)和值(value)组成 。鉴于这两部分会根据存入的值不同而发送变化,我们称之为接口的动态类型动态值

go 复制代码
type Mover interface {
    Move()
}

type Dog struct {
    Name string 
}

func (d *Dog) Move() {
    fmt.Println("狗在跑")
}

type Car struct {
    Brand string
}

func (c *Car) Move() {
    fmt.Println("汽车在跑")
}
go 复制代码
var m Mover
go 复制代码
fmt.Println(m==nil)  // true

此时将一个*Dog结构体赋值给m

go 复制代码
m = &Dog{Name : "旺财"}

为接口变量m赋值一个*Car类型的值

go 复制代码
m = new(Car)
go 复制代码
fmt.Println(m==nil)  //false

此时仅仅是动态值是nil,动态类型不是nil,所以m不等于nil

接口值支持比较,当且仅当接口值的动态类型和动态值相等时相等

go 复制代码
var (
    x Mover = new(Dog)
    y Mover = new(Car)
)

fmt.Println(x==y)   // false

Go 语言中,interface 的内部实现包含了 2 个字段,类型 T 和 值 V,interface 可以使用 == 或 != 比较。2 个 interface 相等有以下 2 种情况

  1. 两个 interface 均等于 nil(此时 V 和 T 都处于 unset 状态)
  2. 类型 T 相同,且对应的值 V 相等。

看下面的例子:

cpp 复制代码
type Stu struct {
	Name string
}

type StuInt interface{}

func main() {
	var stu1, stu2 StuInt = &Stu{"Tom"}, &Stu{"Tom"}
	var stu3, stu4 StuInt = Stu{"Tom"}, Stu{"Tom"}
	fmt.Println(stu1 == stu2) // false
	fmt.Println(stu3 == stu4) // true
}

stu1 和 stu2 对应的类型是 *Stu,值是 Stu 结构体的地址,两个地址不同,因此结果为 false。

stu3 和 stu4 对应的类型是 Stu,值是 Stu 结构体,且各字段相等,因此结果为 true。

总结

  1. 接口类型的值包含动态类型和动态值。
  2. 接口类型的变量支持相互比较,只有当两个变量的动态类型和动态值都相等时两者才相等。
  3. 接口类型的变量支持和nil比较,只有当动态类型和动态值都为nil的时候两者才相等。
相关推荐
小码农<^_^>2 分钟前
c++继承(下)
开发语言·c++
非著名架构师5 分钟前
js混淆的方式方法
开发语言·javascript·ecmascript
Themberfue6 分钟前
基础算法之双指针--Java实现(下)--LeetCode题解:有效三角形的个数-查找总价格为目标值的两个商品-三数之和-四数之和
java·开发语言·学习·算法·leetcode·双指针
深山夕照深秋雨mo15 分钟前
在Java中操作Redis
java·开发语言·redis
努力的布布20 分钟前
SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器
java·后端·spring
PacosonSWJTU25 分钟前
spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)
java·后端·springmvc
barbyQAQ33 分钟前
Qt源码阅读——事件循环
开发语言·数据库·qt
记得开心一点嘛34 分钟前
在Java项目中如何使用Scala实现尾递归优化来解决爆栈问题
开发语言·后端·scala
敏编程1 小时前
网页前端开发之Javascript入门篇(5/9):函数
开发语言·javascript
柏箱1 小时前
PHP基本语法总结
开发语言·前端·html·php