Go语言的类型系统

61 阅读4分钟

前言

实际上类型系统(type system)才是一门编程语言的地基,而对Go来说,整个类型系统更是利用接口将各个部分串联了起来。通过Go强大的类型系统,开发者可以轻松地处理各种数据类型,确保代码的类型安全性和可读性。

基本内容

一个典型的类型系统通常包含如下几个部分

  • 基础类型(char,int,float...)
  • 复合类型(map,array...)
  • 值语义和引用语义
  • 可指向任意对象的类型(any类型,类似Java中的object基类)
  • 接口

基础类型

整数类型(Integer Types) image.png

浮点数类型(Floating-point Types)

类型描述大小(字节)默认值
float3232位浮点数40.0
float6464位浮点数80.0

复数类型(Complex Types)

类型描述大小(字节)默认值
complex6464位复数,实部和虚部都是32位浮点数80.0 + 0.0i
complex128128位复数,实部和虚部都是64位浮点数160.0 + 0.0i

其他类型

类型描述大小(字节)默认值
bool布尔类型1false
byteuint8的别名10
runeint32的别名40
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的接口非常值得单开一篇去详细讲述,感兴趣的话,可以移步此处浏览