前言
实际上类型系统(type system)才是一门编程语言的地基,而对Go来说,整个类型系统更是利用接口将各个部分串联了起来。通过Go强大的类型系统,开发者可以轻松地处理各种数据类型,确保代码的类型安全性和可读性。
基本内容
一个典型的类型系统通常包含如下几个部分
- 基础类型(char,int,float...)
- 复合类型(map,array...)
- 值语义和引用语义
- 可指向任意对象的类型(any类型,类似Java中的object基类)
- 接口
基础类型
整数类型(Integer Types)
浮点数类型(Floating-point Types)
类型 | 描述 | 大小(字节) | 默认值 |
---|---|---|---|
float32 | 32位浮点数 | 4 | 0.0 |
float64 | 64位浮点数 | 8 | 0.0 |
复数类型(Complex Types)
类型 | 描述 | 大小(字节) | 默认值 |
---|---|---|---|
complex64 | 64位复数,实部和虚部都是32位浮点数 | 8 | 0.0 + 0.0i |
complex128 | 128位复数,实部和虚部都是64位浮点数 | 16 | 0.0 + 0.0i |
其他类型
类型 | 描述 | 大小(字节) | 默认值 |
---|---|---|---|
bool | 布尔类型 | 1 | false |
byte | uint8的别名 | 1 | 0 |
rune | int32的别名 | 4 | 0 |
string | 字符串类型 | 不定 | "" |
复合类型
类型 | 描述 |
---|---|
Array | 相同类型,固定大小的元素序列 |
Slice | 动态大小的元素序列 |
Map | 键值对的集合 |
Struct | 结构体,包含不同类型的字段 |
Pointer | 指针,指向其他类型的内存地址 |
Function | 函数类型,用于定义函数的签名 |
Channel | 通道,用于协程间的通信 |
Interface | 接口,定义一组方法,实现接口的类型可被赋值给接口类型 |
func printAnyTypeData(data interface{}) {
fmt.Println(data)
}
printAnyTypeData(42) // 输出: 42
printAnyTypeData("Hello") // 输出: Hello
printAnyTypeData(3.14) // 输出: 3.14
值语义和引用语义
值语义(Value Semantics) : 值语义是指变量在被赋值或传递时,会复制它们的值,每个变量都有自己的独立内存存储。这意味着对一个变量的修改不会影响到其他变量,它们之间是独立的。当值语义的变量传递给函数时,函数的参数是变量的副本,函数对参数的修改不影响原始变量。
引用语义(Reference Semantics) : 引用语义是指变量在被赋值或传递时,实际上是传递了指向同一内存地址的引用。多个变量共享同一块内存,因此对其中一个变量的修改会影响到其他变量。当引用语义的变量传递给函数时,函数的参数是原始变量的引用,函数对参数的修改会直接影响到原始变量。
Go语言中的很多类型都基于值语义,包括:
- 基本类型(整数、浮点数...)
- 复合类型(数组)
而切片、映射、通道和指针等复合类型具有引用语义,它们在赋值或传递给函数时只是传递了指向底层数据的引用,多个变量可以共享同一份数据。
值语义示例:
x = 100
}
func main() {
num1 := 42
num2 := num1 // 复制num1的值给num2
fmt.Println(num1) // 输出: 42
fmt.Println(num2) // 输出: 42
modifyInt(num1)
fmt.Println(num1) // 输出: 42,因为num1的值被复制到函数中的参数,num1本身没有被修改
}
引用语义示例:
func modifySlice(s []int) {
s[0] = 100
}
func main() {
slice1 := []int{1, 2, 3}
slice2 := slice1 // 传递slice1的引用给slice2
fmt.Println(slice1) // 输出: [1 2 3]
fmt.Println(slice2) // 输出: [1 2 3]
modifySlice(slice1)
fmt.Println(slice1) // 输出: [100 2 3]
fmt.Println(slice2) // 输出: [100 2 3]
//slice1,slice2被修改了,slice1和slice2共享同一块内存
}
可指向任意对象的类型
根据Go的源代码type any = interface{}
可知,any是interface{}的别名。
而空接口类型(interface{})是一种特殊的接口类型,它可以表示任意类型的对象。这类似于Java中的Object基类,它是所有类的根类,可以表示任何对象。
在Go中,空接口广泛应用于需要处理未知类型数据的场景,可以使用它实现通用的数据容器。在不知道具体类型的情况下,将任意类型的值赋值给变量,并传递给函数,这同时也会引入类型断言或类型判断的需求(如果需要的话)。
接口
Go语言中的非侵入式接口很特别,它定义了一组方法的集合。任何类型只要实现了接口中定义的所有方法,就被认为实现了该接口。接口使得代码更加灵活和通用,允许在不修改现有代码的情况下扩展和替换组件。
本文不会对Go的接口过多介绍,这是因为Go的接口非常值得单开一篇去详细讲述,感兴趣的话,可以移步此处浏览。