问题
- Go 中
byte
和rune
的别名是什么? - Go 语言中的组合类型有哪些?
- 什么是类型定义?如何与类型别名区分?
- Go 语言从哪个版本开始支持泛型?
- 如何理解 Go 中的底层类型?
- 什么是零值?举例说明。
- 接口类型的动态值和动态类型是什么?
- 如何判断一个类型是否实现了某个接口?
- Go 中哪些类型是不可比较的?
- 通道类型有哪些方向?
1. 基本类型(Basic Types)
- 定义:Go 语言中预定义的基础类型。
- 示例:
- 字符串类型:
string
- 布尔类型:
bool
- 数值类型:包括多种整数类型(如
int8
、uint8
)、浮点类型(如float32
、float64
)、复数类型(如complex64
、complex128
)。
- 字符串类型:
- 注意:
byte
是uint8
的别名,rune
是int32
的别名。
2. 组合类型(Composite Types)
- 定义:通过组合其他类型构成的新类型。
- 示例:
- 指针类型:类似 C 语言的指针。
- 结构体类型:类似 C 语言中的结构体。
- 函数类型:在 Go 中,函数是一等公民。
- 容器类型:
- 数组:固定长度。
- 切片:动态长度。
- 映射(map):键值对集合。
- 通道类型:用于协程间通信。
- 接口类型:支持多态和反射。
3. 类型定义(Type Definition)
- 定义:创建新的类型标识符,使其与源类型不同。
- 示例:
1 2
type MyInt int type Book struct { title string; pages int }
- 注意:定义的类型与源类型不同,但它们的底层类型相同,可进行显式转换。
- 一个新定义的类型和它的源类型为两个不同的类型。
- 在两个不同的类型定义中所定义的两个类型肯定是两个不同的类型。
- 一个新定义的类型和它的源类型的底层类型)一致并且它们的值可以相互显式转换。
- 类型定义可以出现在函数体内。
4. 类型别名(Type Alias)
- 定义:为现有类型创建新的标识符,使其表示同一类型。
- 示例:
1 2
type Name = string type Table = map[string]int
- 注意:别名与原类型共享底层类型。
5. 泛型类型(Generic Types)
- 定义:从 Go 1.18 开始支持,通过类型参数实现类型的泛化。
- 概念:类型约束、类型参数。
- 实例化:泛型类型必须被实例化为具名类型才能使用。
6. 具名类型与无名类型(Named vs Unnamed Types)
- 具名类型:有标识符表示的类型(预声明类型、定义类型)。
- 无名类型:没有标识符的类型,通常是组合类型。
7. 底层类型(Underlying Type)
- 定义:每个类型都有一个底层类型。
- 示例:
1
type MyInt int // MyInt 的底层类型是 int
如何溯源一个声明的类型的底层类型?规则很简单,在溯源过程中,当遇到一个内置类型或者无名类型时,溯源结束。 以上面这几个声明的类型为例,下面是它们的底层类型的溯源过程:
MyInt → int Age → MyInt → int IntSlice → []int MyIntSlice → []MyInt → []int AgeSlice → []Age → []MyInt → []int Ages → AgeSlice → []Age → []MyInt → []int
在Go中,
- 底层类型为内置类型
bool
的类型称为布尔类型; - 底层类型为任一内置整数类型的类型称为整数类型;
- 底层类型为内置类型
float32
或者float64
的类型称为浮点数类型; - 底层类型为内置类型
complex64
或complex128
的类型称为复数类型; - 整数类型、浮点数类型和复数类型统称为数字值类型;
- 底层类型为内置类型
string
的类型称为字符串类型。
8. 值(Value)
- 定义:类型的实例称为值,每个类型有一个零值。
- 零值示例:
nil
是切片、映射、函数、通道、指针、接口的零值。
9. 值部(Value Part)
- 定义:每个值在内存中的存储部分,包含直接和间接部分。 非官方定义 值部这个术语并没有在Go白皮书中定义。它仅使用在《Go语言101》这本书中,用来简化一些解释并帮助Go程序员更好地理解Go类型和值。
10. 值尺寸(Value Size)
- 定义:值在内存中占据的字节数。
- 工具:
unsafe.Sizeof
可用于获取值的尺寸。
11. 指针类型的基类型(Base Type of Pointer Types)
- 定义:指针类型的基类型是其指向的类型。
- 示例:
*int
的基类型是int
。
12. 结构体类型的字段(Field)
- 定义:结构体由多个字段组成。
- 示例:
1 2 3 4 5
struct { author string title string pages int }
13. 函数类型的签名(Signature)
- 定义:由函数的参数和返回类型列表组成。
14. 接口类型的动态类型和动态值
- 定义:接口值包裹的非接口值为动态值,其类型为动态类型。
接口类型的动态类型和动态值
接口值:在 Go 中,接口类型的值被称为接口值。接口值是可以包裹一个非接口值的。
动态值与动态类型:
- 动态值:包裹在接口值中的非接口值被称为动态值。
- 动态类型:动态值的类型被称为动态类型。
零值接口值:如果一个接口值没有包裹任何非接口值,则它是一个零值接口值。在这种情况下,零值接口值的动态值和动态类型均不存在。
实现接口:
- 一个接口类型可以定义若干个方法,这些方法形成了该接口的方法集。
- 若一个类型的方法集是某接口类型的方法集的超集,则该类型被认为实现了该接口类型。这意味着,这个类型的实例可以赋值给该接口类型的变量。
举例说明:
- 例如,假设有一个接口
Shape
,它定义了一个方法Area
。
1 2 3
type Shape interface { Area() float64 }
- 如果有一个类型
Circle
,它定义了Area
方法:
1 2 3 4 5 6 7
type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius }
- 那么,
Circle
类型实现了Shape
接口,因为Circle
的方法集包含了Shape
的所有方法。
- 例如,假设有一个接口
通过理解这些概念,可以更好地掌握 Go 语言中的接口机制及其在多态性和代码复用中的作用。接口类型的动态类型和动态值是 Go 语言实现多态的重要方式。
15. 容器类型(Container Types)
- 定义与示例:
- 数组、切片、映射是正式的容器类型。
- 通道、字符串有时也视作容器类型。
16. 映射类型的键值类型(Key Type of Map Types)
- 定义:映射中的键必须是可比较类型。
17. 通道类型的方向(Channel Direction)
- 定义:通道可以是双向、只读或只写。
- 示例:
- 双向:
chan T
- 只写:
chan<- T
- 只读:
<-chan T
- 双向:
18. 可比较和不可比较类型
- 可比较类型:可以用 == 和 != 比较。
- 不可比较类型:切片、映射、函数类型等。
19. 面向对象编程支持
- 支持:Go 支持方法、实现和类型内嵌的面向对象编程元素。
20. 泛型支持
- 历史:Go 1.18 开始支持自定义泛型。
这些概念构成了 Go 类型系统的重要部分,理解这些概念有助于掌握 Go 语言编程。
问题与答案
Go 中
byte
和rune
的别名是什么?byte
是uint8
的别名,rune
是int32
的别名。
Go 语言中的组合类型有哪些?
- 组合类型包括指针类型、结构体类型、函数类型、数组、切片、映射(map)、通道类型和接口类型。
什么是类型定义?如何与类型别名区分?
- 类型定义:创建新的类型标识符,使其与源类型不同。例如,
type MyInt int
。 - 类型别名:为现有类型创建新的标识符,表示同一类型。例如,
type Name = string
。
- 类型定义:创建新的类型标识符,使其与源类型不同。例如,
Go 语言从哪个版本开始支持泛型?
- 从 Go 1.18 版本开始支持泛型。
如何理解 Go 中的底层类型?
- 每个类型都有一个底层类型。底层类型是指在溯源过程中遇到的内置类型或无名类型。例如,
type MyInt int
的底层类型是int
。
- 每个类型都有一个底层类型。底层类型是指在溯源过程中遇到的内置类型或无名类型。例如,
什么是零值?举例说明。
- 零值是类型的默认值,例如,
nil
是切片、映射、函数、通道、指针、接口的零值。
- 零值是类型的默认值,例如,
接口类型的动态值和动态类型是什么?
- 动态值:包裹在接口值中的非接口值。
- 动态类型:动态值的类型。
如何判断一个类型是否实现了某个接口?
- 如果一个类型的方法集是某接口类型的方法集的超集,则该类型实现了该接口。例如,
Circle
类型有Area
方法,则实现了Shape
接口。
- 如果一个类型的方法集是某接口类型的方法集的超集,则该类型实现了该接口。例如,
Go 中哪些类型是不可比较的?
- 切片、映射、函数类型是不可比较类型,不能用 == 和
!=
操作符比较。
- 切片、映射、函数类型是不可比较类型,不能用 == 和
通道类型有哪些方向?
- 通道类型可以是双向(
chan T
)、只写(chan<- T
)、只读(<-chan T
)。
- 通道类型可以是双向(