面向对象编程(OOP)是软件开发中的重要理念,虽然Go语言的方式与传统的OOP有些不同,但它依然支持这些基本特性。本文将简要介绍Golang如何使用结构体实现面向对象的三大特性:封装、继承和多态。

1.结构体的定义

由于Golang中没有类的概念,因此Golang中的struct和其他语言中的class有着同等的地位,可以使用struct来实现面向对象的诸多特性。

type Student struct {
	Name string 
	Age  int    
	ID   int    
}

func main() {
	// 先定义 后赋值
	var s1 Student
	s1.Name = "luoaoxuan"
	s1.Age = 21
	s1.ID = 1001
	// 定义时赋值
	s2 := Student{"tangjiaxian", 25, 1005}
	// 使用new关键字创建对象指针
	var s3 *Student = new(Student)
	s3.Name = "luaox"
	s3.Age = 18
	s3.ID = 1006
	// 按key赋值
	s4 := Student{
		Name: "tjx",
		Age:  40,
		ID:   1007,
	}
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(*s3)
	fmt.Println(s4)
}

注意,GO语言中的结构体指针类型变量,在访问结构体中的成员变量时,可以直接使用点.不用使用箭头->.并且结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字,个数和类型).GO语言中的type相当于取别名,取的别名GO语言认为它是一种新的数据类型

2.方法的实现

在Golang中,方法和函数的不同在于书写方式的不同,方法需要与结构体进行绑定。

func speak1() {
	fmt.Println("函数-学生说")
}
func (s Student) speak2() {
	fmt.Println("方法-学生说")
}

func main() {
	s2 := Student{"tangjiaxian", 25, 1005}
	speak1() // 函数
	s2.speak2() // 方法
}

上面的代码中,speak2就是结构体方法,第一个括号内容: (s Student),证明这个方法绑定的是结构体Student,只有结构体Student变量才能访问这个方法,并且这个代码中的方法是结构体对象的值传递,所以方法内修改是不会影响外面的变量的。

3.封装的实现

在Golang中,没有public,private,protected等关键字,一般是通过变量名的大小写来控制变量的访问范围,大写字母开头的属性是包外可用的,小写字母开头的属性是只有包内可用的。Golang包内声明的变量、结构体、类型、函数等都是一样的规则,大写字母开头则对外可见,反之对外不可见。

type Student struct {
	Name string
	Age  int
	ID   int
	sex  string  // 私有 只有包内能访问
}
func (s *Student) SetSex(sex string) {
	s.sex = sex
}
func (s *Student) GetSex() string {
	return s.sex
}

4.继承的实现

在Golang中,如果一个struct嵌套了另外一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承特性。

type People struct {
	Name string
}

type Student struct {
	StudentId int
	People //复用父类,加入匿名结构体
}

func main() {
	s := Student{}
	s.StudentId = 1001
	s.Name = "luoaoxuan"
	// 等价于 s.People.Name = "luoaoxuan"
	fmt.Println(s)
}

注意,这里变量s是Student类型,它访问父类People类中的变量或方法时,可以直接用.访问到,而不是使用s.People.Name 的方式,GO语言在这一块做了简化。并且不建议将父类和子类的变量重名。GO语言支持多继承,即一个结构体嵌套多个匿名结构体。

5.接口与多态

接口的存在是为了定义规则,规范或某种具体的功能,它需要使用interface关键字,使用结构体和接口可以实现多态特性。

type Cat struct {
	Name string
}
type Dog struct {
	Name string
}
type Animal interface {
	speak() //声明一个没有实现的方法
}
//实现具体的方法
func (c Cat) speak() {
	fmt.Println("喵~")
}
//实现具体的方法
func (d Dog) speak() {
	fmt.Println("旺~")
}
func call(a Animal) {
	a.speak()
}
func main() {
	c := Cat{}
	d := Dog{}
	call(c)
	call(d)
}

上例实现了动物的接口,动物都会叫,只要实现了叫的方法,我们就认为其是动物,因此猫是动物,狗也是动物,因为它们都会叫。即实现了多态。
注意,在Golang中,interface{}代表空接口,任何类型都可以看作空接口,空接口是所有类的父类。