返回

Go 面向对象详解

后端

Go 是一个静态强类型语言,它支持面向对象编程(OOP),允许程序员使用类和对象来组织代码。

OOP 是一种将数据和行为组合在一起的编程方式。数据存储在对象中,而行为则通过方法来实现。

在 Go 中,可以使用 struct 来定义对象,struct 是一个包含一组字段的类型。字段可以是任何类型,包括基本类型(如 int、float64、bool 等)、其他 struct 类型、指针类型等。

例如,我们可以定义一个 Person struct 来表示一个人:

type Person struct {
    name string
    age  int
}

这个 Person struct 有两个字段:nameage

我们可以使用 new 来创建一个 Person 对象:

p := new(Person)

现在,我们就可以使用点运算符来访问 p 对象的字段:

fmt.Println(p.name)  // ""
fmt.Println(p.age)   // 0

也可以使用 & 操作符来获取 p 对象的地址:

pPtr := &p
fmt.Println(pPtr.name)  // ""
fmt.Println(pPtr.age)   // 0

在 Go 中,方法是附属在一个给定的类型上的函数。方法的语法和函数的声明语法几乎一样,只是在 func 后面增加了一个接收者。

接收者可以是任何类型,包括基本类型(如 intfloat64bool 等)、其他 struct 类型、指针类型等。

例如,我们可以为 Person struct 定义一个 setName 方法来设置一个人的名字:

func (p *Person) setName(name string) {
    p.name = name
}

在这个 setName 方法中,接收者是 *Person 类型,表示该方法可以被 Person 类型的值或 Person 类型的值的指针调用。

现在,我们就可以使用点运算符来调用 setName 方法:

p.setName("Alice")
fmt.Println(p.name)  // "Alice"

也可以使用 & 操作符来获取 p 对象的地址,然后使用点运算符来调用 setName 方法:

pPtr := &p
pPtr.setName("Bob")
fmt.Println(p.name)  // "Bob"

在 Go 中,继承是通过嵌入的方式实现的。一个 struct 可以嵌入另一个 struct,从而继承另一个 struct 的字段和方法。

例如,我们可以定义一个 Student struct 来表示一个学生,Student struct 嵌入 Person struct:

type Student struct {
    Person
    grade int
}

现在,Student struct 就继承了 Person struct 的 nameage 字段,以及 setName 方法。

我们可以使用 new 关键字来创建一个 Student 对象:

s := new(Student)

现在,我们就可以使用点运算符来访问 s 对象的字段:

fmt.Println(s.name)  // ""
fmt.Println(s.age)   // 0
fmt.Println(s.grade) // 0

也可以使用 & 操作符来获取 s 对象的地址:

sPtr := &s
fmt.Println(sPtr.name)  // ""
fmt.Println(sPtr.age)   // 0
fmt.Println(sPtr.grade) // 0

在 Go 中,多态性是通过接口实现的。接口是一个定义了一组方法的类型。任何类型只要实现了接口定义的方法,就可以被视为该接口的类型。

例如,我们可以定义一个 Speaker 接口,该接口定义了一个 speak 方法:

type Speaker interface {
    speak()
}

现在,我们可以让 Person struct 和 Student struct 都实现 Speaker 接口:

func (p *Person) speak() {
    fmt.Println("Hello, my name is", p.name)
}

func (s *Student) speak() {
    fmt.Println("Hello, my name is", s.name, "and I'm a student.")
}

现在,我们可以使用 Speaker 接口来定义一个函数,该函数可以接受任何实现了 Speaker 接口的类型的值:

func greet(s Speaker) {
    s.speak()
}

现在,我们可以将 Person 对象和 Student 对象都传递给 greet 函数:

p := new(Person)
p.setName("Alice")

s := new(Student)
s.setName("Bob")
s.grade = 1

greet(p)  // "Hello, my name is Alice"
greet(s)  // "Hello, my name is Bob and I'm a student."

在 Go 中,封装是通过访问控制来实现的。访问控制允许我们控制哪些字段和方法可以被其他包或类型访问。

在 Go 中,有三个访问控制级别:

  • public:表示该字段或方法可以被任何包或类型访问。
  • private:表示该字段或方法只能被定义该字段或方法的包或类型访问。
  • package:表示该字段或方法只能被定义该字段或方法的包中的类型访问。

例如,我们可以定义一个 secret 字段,该字段只能被 Person struct 本身访问:

type Person struct {
    name string
    age  int
    secret string
}

现在,其他包或类型无法访问 secret 字段。

面向对象编程是一种强大的编程范式,它可以帮助我们组织代码,使代码更易于维护和理解。Go 支持面向对象编程,允许程序员使用类和对象来组织代码。