问题

  1. Go 中 byterune 的别名是什么?
  2. Go 语言中的组合类型有哪些?
  3. 什么是类型定义?如何与类型别名区分?
  4. Go 语言从哪个版本开始支持泛型?
  5. 如何理解 Go 中的底层类型?
  6. 什么是零值?举例说明。
  7. 接口类型的动态值和动态类型是什么?
  8. 如何判断一个类型是否实现了某个接口?
  9. Go 中哪些类型是不可比较的?
  10. 通道类型有哪些方向?

参考Go类型系统概述 -Go语言101

1. 基本类型(Basic Types)

  • 定义:Go 语言中预定义的基础类型。
  • 示例
    • 字符串类型:string
    • 布尔类型:bool
    • 数值类型:包括多种整数类型(如 int8uint8)、浮点类型(如 float32float64)、复数类型(如 complex64complex128)。
  • 注意byteuint8 的别名,runeint32 的别名。

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的类型称为浮点数类型
  • 底层类型为内置类型complex64complex128的类型称为复数类型
  • 整数类型、浮点数类型和复数类型统称为数字值类型
  • 底层类型为内置类型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 语言编程。


问题与答案

  1. Go 中 byterune 的别名是什么?

    • byteuint8 的别名,runeint32 的别名。
  2. Go 语言中的组合类型有哪些?

    • 组合类型包括指针类型、结构体类型、函数类型、数组、切片、映射(map)、通道类型和接口类型。
  3. 什么是类型定义?如何与类型别名区分?

    • 类型定义:创建新的类型标识符,使其与源类型不同。例如,type MyInt int
    • 类型别名:为现有类型创建新的标识符,表示同一类型。例如,type Name = string
  4. Go 语言从哪个版本开始支持泛型?

    • 从 Go 1.18 版本开始支持泛型。
  5. 如何理解 Go 中的底层类型?

    • 每个类型都有一个底层类型。底层类型是指在溯源过程中遇到的内置类型或无名类型。例如,type MyInt int 的底层类型是 int
  6. 什么是零值?举例说明。

    • 零值是类型的默认值,例如,nil 是切片、映射、函数、通道、指针、接口的零值。
  7. 接口类型的动态值和动态类型是什么?

    • 动态值:包裹在接口值中的非接口值。
    • 动态类型:动态值的类型。
  8. 如何判断一个类型是否实现了某个接口?

    • 如果一个类型的方法集是某接口类型的方法集的超集,则该类型实现了该接口。例如,Circle 类型有 Area 方法,则实现了 Shape 接口。
  9. Go 中哪些类型是不可比较的?

    • 切片、映射、函数类型是不可比较类型,不能用 == 和 != 操作符比较。
  10. 通道类型有哪些方向?

    • 通道类型可以是双向(chan T)、只写(chan<- T)、只读(<-chan T)。