Go Basic:理解方法,接口,结构嵌入,泛型:涵盖Go中的OOP概念

让我们进入 Go 中令人兴奕的面向对象编程(OOP)的世界!

full lessons here👇:
https://programmerscareer.com/zh-cn/golang-basic-skill/

由AI生成,可能有错误,仅供参考

Topic: Go 对象导向编程介绍

历史上,Go语言被认为不支持传统的对象导向编程语义。这然而不是完全准确。在 Go 中,我们不能像 Java 或 Python 一样创建类,但是我们可以在类型上定义方法。这是 Go 的一种方式,让我们为自己的类型定义行为,这与其他语言中的“类”概念相似。

Topic: Go 结构体

结构体(或 structs)是 Go 中的自定义类型,它们将零个或多个其他类型组合起来。

我们使用 type 关键字,后跟结构体名称和 struct 关键字来定义新的结构体类型。实际结构体字段定义包含在大括号 {} 中。

以下是一个基本示例:

1
2
3
4
type Person struct {
Name string
Age int
}

在这个示例中,我们定义了一个名为 Person 的新类型,它有两个字段:Name 是字符串,Age 是整数。

然后,我们可以创建 Person 结构体实例:

1
2
3
p := Person{"John Doe", 30}
fmt.Println(p.Name) // 输出:John Doe
fmt.Println(p.Age) // 输出:30

在 Go 中,. 操作符用于访问结构体实例的字段。正如 structs 是非常有用的,它们可以将相关数据组合起来。这是 Go 对象导向编程语言的一种方式。

Topic: Go 方法

在 Go 中,方法是一个与特定类型相关的函数。类型上的方法提供了 Go 编程语言中的“对象导向”感觉,即使严格来说,Go 不支持对象或类。以下是一个简单示例,演示如何在 Go 中声明一个方法:

1
2
3
4
5
6
7
type Circle struct {
Radius float64
}

func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}

在这个示例中,我们定义了一个名为 Circle 的新类型,然后定义了一个名为 Area() 的方法,该方法操作于 Circle 类型。

1
2
c := Circle{10}
fmt.Println(c.Area()) // 输出:314.1592653589793

这个示例很有趣,因为现在我们可以在 Circle 实例上直接调用函数,这与 Java 或 JavaScript 中对对象的方法调用类似。

Topic: Go 指针接收器

在 Go 中,我们还可以声明指针接收器方法。这意味着接收器类型前面有 * 操作符。以下是一个示例:

1
2
3
4
5
6
7
8
type Employee struct {
Name string
Salary int
}

func (e *Employee) giveRaise(amount int) {
e.Salary += amount
}

在这个示例中,giveRaise() 是一个指针接收器方法,它的 receiver 类型是 Employee。现在,当我们调用 giveRaise() 时,它将修改原始 Employee 变量,因为它拥有对原始项的引用。

1
2
3
e := Employee{"John", 5000}
e.giveRaise(1000)
fmt.Println(e.Salary) // 输出:6000

你可能会问,为什么和何时使用指针接收器?

  1. 如果我们需要修改 receiver,我们应该使用指针接收器。像 giveRaise() 示例。
  2. 如果结构体很大,指针接收器将更有效,因为它不需要复制整个结构体。

Topic: Go 中的接口

Go 中的接口是一个简单地定义了一组方法的类型。如果其他类型实现了这些方法,那么该类型就被认为实现了这个接口。下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Shape interface {
Area() float64
}

type Circle struct {
Radius float64
}

func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}

type Rectangle struct {
Width, Height float64
}

func (r Rectangle) Area() float64 {
return r.Width * r.Height
}

在这个代码中,我们定义了一个名为 Shape 的接口,它只有一个方法 Area()。然后我们定义了两个不同的结构体,CircleRectangle,每个结构体都有一个 Area() 方法。现在,CircleRectangle 都实现了 Shape 接口。我们可以将 CircleRectangle 的实例视为 Shape

1
2
3
4
5
6
7
8
func printArea(s Shape) {
fmt.Println(s.Area())
}

c := Circle{10}
r := Rectangle{10, 20}
printArea(c) // 输出:314.1592653589793
printArea(r) // 输出:200

Go 的接口不同于其他语言。Go 中,我们不需要显式地声明一个类型实现了一个接口。如果一个类型提供了一个接口所需的所有方法,那么它自动实现了该接口。

Topic: Go 中的结构体嵌套和组合

在 Go 中,我们可以将一个结构体嵌套在另一个结构体中。这称为“嵌套”,它提供了一些继承的好处,但更简单、更安全。在对象oriented 概念中,它更像组合(将简单的对象组合成复杂的对象)而不是继承。下面是一个示例:

1
2
3
4
5
6
7
8
9
10
type Person struct {
Name string
Age int
}

type Employee struct {
Person
Position string
Salary int
}

在上面的示例中,Employee 结构体嵌套了 Person 结构体,这意味着它包含了 Person 的所有字段和方法。

我们可以访问 Person 结构体的字段直接从 Employee 中。实际上,它们就像存在于 Employee 结构体中:

1
2
3
4
5
6
7
8
9
10
11
e := Employee{
Person: Person{
Name: "Bob",
Age: 30,
},
Position: "Developer",
Salary: 80000,
}
fmt.Println(e.Name) // 输出:Bob
fmt.Println(e.Age) // 输出:30
fmt.Println(e.Salary) // 输出:80000

Topic: Go 中的泛型

Go 1.18 将引入泛型,这是 Go 中最期待的特性。泛型可以使您的程序更加灵活和可维护,通过表示一系列类型,而不是单个类型。在下面是一个简单的示例:

1
2
3
4
5
6
7
8
9
10
func PrintSlice[T any](s []T) {
for _, v := range s {
fmt.Println(v)
}
}

func main() {
PrintSlice[int]([]int{1, 2, 3, 4, 5})
PrintSlice[string]([]string{"Hello", "World"})
}

在这个代码中,PrintSlice[T any](s []T) 是一个泛型函数,它可以工作于任何类型的 slice 中。T 是一个类型参数,它表示任何类型。any 关键字意味着 T 可以是任何类型:int、float、string 等,包括用户定义的类型!

main 函数中,我们使用 PrintSlice 函数来处理 int 和 string 的 slice。这展示了 PrintSlice 是一个泛型函数。

这个示例给您一个基本的了解如何在 Go 中使用泛型。

English post: https://programmerscareer.com/go-basic-04/
作者:Wesley Wei – Twitter Wesley Wei – Medium
注意:本文为作者原创,转载请注明出处。

Go基础:了解 Atomic, Mutex, Stateful Goroutines in Go Go基础:理解For, If Else, Switch, Functions, Range, 闭包, 递归

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×