跳转至

Golang

数据结构

Golang 的数据结构主要包括 数组、切片、哈希表。

Golang 中的 切片Slice 类似于 Rust 中的 Vector,而不类似于 Rust 中的 切片Slice

标准库的数据结构比较少,例如没有Hashset(虽然可以用map[T]struct{}平替)。GoDS 提供了更多的数据结构。

make关键字是Golang专门用来创建这些自带的数据结构的。

Go 语言的接口 ^ai

Go 语言并不是一个典型的鸭子类型(duck typing)语言。鸭子类型是一个动态类型概念,其核心思想是“如果它走路像鸭子,叫声也像鸭子,那么它就是鸭子”。这种类型系统不在乎对象的类型,而是在乎对象是否有某种行为(即对象的方法或属性)。

Go 语言采用的是静态类型系统,这意味着变量的类型在编译时就已确定,而不是在运行时。但是,Go 语言支持一种特性,也让它在某种程度上展现出类似鸭子类型的行为,这就是接口(interface)。

Go 的接口类型是一种抽象类型,它定义了一个方法集。任何具有这些方法的类型都自动满足该接口,无需显式声明实现了哪个接口。这种机制被称为隐式接口实现。例如:

type Talker interface {
    Talk() string
}

type Dog struct {}

func (d Dog) Talk() string {
    return "Woof!"
}

type Cat struct {}

func (c Cat) Talk() string {
    return "Meow!"
}

在这个例子中,DogCat 类型都没有显式声明它们实现了 Talker 接口,但是由于它们都定义了 Talk 方法,所以它们都满足 Talker 接口。

在使用接口的地方,Go 表现出与鸭子类型类似的行为:只要一个类型具有接口所需的所有方法,它就可以被视为该接口类型(也可以说是隐式地实现了接口)。这允许在不知道对象确切类型的情况下,通过接口操作这些对象。然而,这种行为仍然在静态类型的框架内进行,因为所有检查都是在编译时完成的。

虽然 Go 的接口提供了一种灵活的方式来处理不同类型的对象,但它并不是真正意义上的鸭子类型,因为它依赖静态类型检查,而不是运行时的类型决定。Go 的接口更多地提供了一种类型安全的多态机制,使得代码可以在保持类型安全的同时,具有很高的灵活性和扩展性。

Select 关键字

select 是 Linux 中的系统调用,我们经常会使用 selectpollepoll 等函数构建 I/O 多路复用模型提升程序的性能。Go 语言的 select 与 Linux 中的 select 比较相似。select 系统调用可以同时监听多个文件描述符的可读或者可写的状态,Go 语言中的 select 也能够让 Goroutine 同时等待多个 Channel 可读或者可写,在多个文件或者 Channel状态改变之前,select 会一直阻塞当前线程或者 Goroutine。

参数传递

Golang 使用了值传递作为参数传递的方式。无论是传递基本类型、结构体还是指针,都会对传递的参数进行拷贝。因此,在传递数组或者内存占用非常大的结构体时,我们应该尽量使用指针作为参数类型来避免发生数据拷贝进而影响性能。

反射

运行时反射是程序在运行期间检查其自身结构的一种方式。反射带来的灵活性是一把双刃剑,反射作为一种元编程方式可以减少重复代码,但是过量的使用反射会使我们的程序逻辑变得难以理解并且运行缓慢。

一个典型的使用反射的例子是JSON的反序列化。

Chan

通道关闭后的行为:

  1. 当一个通道被关闭后,你仍然可以从该通道接收数据,直到通道中的缓冲数据被完全读取完毕。
  2. 一旦通道中的数据被读取完毕,任何进一步的接收操作将立即完成,并返回该通道元素类型的零值。
  3. 向已关闭的通道发送数据将导致运行时 panic。