跳到主要内容

Go 类型别名和自定义类型

使用类型别名简化参数

在 Go 语言中,我可以使用类型别名来简化函数参数的定义,使代码更加清晰易读。

package main

func main() {
// 定义类型别名,简化回调函数的参数类型
type ComputeCallback = func(a, b int, operator string, result int) string

compute := func(a, b int, operator string, callback ComputeCallback) string {
result := a + b // 可以根据 operator 执行不同的运算
return callback(a, b, operator, result)
}
}

在这个示例中,我使用 type 定义了一个函数类型的别名 ComputeCallback,这使得在定义 compute 函数时,参数类型更为简洁明了。

类型别名和自定义类型的区别

自定义类型

自定义类型是基于现有类型创建的全新类型,虽然具有相同的底层结构,但被视为不同的类型。

type MyInt int

在这个例子中,MyInt 是一个新的类型,基于 intMyIntint 并不相同,不能直接互换使用,需要进行显式类型转换。我还可以为 MyInt 定义方法。

类型别名

类型别名是为现有类型创建一个新的名称,类型别名与原类型完全相同,可以互换使用。

type MyInt = int

这里,MyIntint 的别名,它们是完全相同的类型。这种方式主要用于代码重构,便于逐步替换类型名称,而不影响现有代码。

关键区别

自定义类型和类型别名有以下几个关键区别:

首先,在方法定义方面,自定义类型可以定义新的方法,而类型别名不能。对于自定义类型,我可以为其添加方法,以扩展其功能;而类型别名则共享原类型的方法,无法新增。

其次,在类型兼容性方面,自定义类型与其基础类型不兼容,需要显式转换。类型别名与原类型完全兼容,可以直接互换使用。这意味着,自定义类型可以提供更严格的类型检查。

最后,在使用场景上,自定义类型适用于需要创建新类型并添加方法或特殊行为的情况。类型别名适用于代码重构,逐步迁移类型名称,减少一次性修改带来的风险。

使用结构体时的注意事项

在使用结构体时,需要注意以下几点。

零值

未初始化的结构体字段将被设置为其类型的零值。int 的零值是 0string 的零值是空字符串。

指针与值类型

结构体可以通过值或指针传递:

  • 使用指针传递结构体可以避免复制整个结构体,节省内存,特别是对于大型结构体。
  • 如果需要在方法中修改结构体的字段,应该使用指针作为方法的接收者。

封装

Go 语言通过标识符的大小写来控制可见性:

  • 首字母大写的字段或方法是导出的,可以被其他包访问。
  • 首字母小写的字段或方法是未导出的,只能在包内访问。

组合而非继承

Go 提倡使用组合来复用代码,而不是传统的继承 😊。可以在一个结构体中嵌入另一个结构体,以实现字段和方法的复用。

type Engine struct {
Power int
}

type Car struct {
Engine
Brand string
}

func (e *Engine) Start() {
// 启动引擎的逻辑
}

func main() {
myCar := Car{
Engine: Engine{Power: 150},
Brand: "Toyota",
}

myCar.Start() // 可以直接调用嵌入的 Engine 的方法
}

在这个例子中,Car 结构体嵌入了 Engine 结构体,这样 Car 就拥有了 Engine 的所有字段和方法,实现了代码的复用。

注意事项

在编写 Go 语言代码时,理解类型别名和自定义类型的区别,以及在使用结构体时的各种注意事项,有助于写出更清晰、高效的代码。