Struct(结构体) Link to heading

Golang 中没有提供class 这一面向对象的概念,所以也不存在继承这一面向对象的一大特性。于此同时为了实现类似面向对象的一些特性,Golang 提供了StructInterface这两个语法。通过结构体的内嵌配合接口,同样可以实现类似面向对象编程的效果。

Go 语言中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,这时候再用单一的基本数据类型明显就无法满足需求了,Go 语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称 struct。 也就是我们可以通过 struct 来定义自己的类型了。

// go_structs.go

package main

import "fmt"

// 定义结构体
// 这里需要注意!!!
// 下面Person 结构体及结构体字段首字母均为大写
// 在Golang中不同于Ruby,命名规范上推荐使用用驼峰命名
// 若一个包中的 函数,结构体,等定义是时 首字母为小写.
// 则该函数、结构体只能在当前包内使用,若为大写则可在其他包Import时在其他包内使用
// 结构体中的字段可以用成员变量来理解,类似于Ruby中类的属性

type Person struct {
	Name    string
	Age     int
	Addrs   string
	StepNum int
}

// 方法
// Golang中将函数和方法做了区分(也肯能是我自己一直没有区分,不过问题不大)
// Golang 的方法 需要一个接收者(receiver)这点和Ruby类似
// 只能为当前包内定义的类型 定义方法
// 同时方法的接收者 可以是一个值 也可以是一个指针
// 同时不支持方法重载

// 实现 Person 的实例方法

// 接收者类型为指针
func (p *Person) addStep(i int) {
	p.StepNum += i
}

// 接收者类型为Value
func (p Person) sayHello() {
	fmt.Printf("%v say: Hello !!!\n", p.Name)
}

func (p Person) afterTenYearAge() int {
	return p.Age + 10
}

func printPerson(p Person) {

	fmt.Printf("Name: %v, Age: %d, Addrs: %v, StepNum: %d\n", p.Name, p.Age, p.Addrs, p.StepNum)
}

func main() {
	// 实例化一个结构体
	liming := Person{Name: "李明", Age: 18, Addrs: "北京", StepNum: 180}

	// 若不对属性进行赋值则会使用对应类型的0值
	lilei := Person{Name: "李磊", Age: 17}

	printPerson(liming)
	printPerson(lilei)

	// 更新结构体实例
	lilei.StepNum = 170
	liming.Age = 20
	fmt.Println("\n===========================\n")
	printPerson(liming)
	printPerson(lilei)

	fmt.Println("\n===========================\n")
	// 调用指针类型
	// 这里没用使用& 进行寻址,但是方法调用用成功
	// 因为编译器做了自动转换
	liming.addStep(20)

	// 调用值类型
	liming.sayHello()
	printPerson(liming)

	lm := &liming
	lm.addStep(25)
	printPerson(liming)

	afterAge := liming.afterTenYearAge()
	fmt.Println(afterAge)

}
$ go run go_structs.go

Name: 李明, Age: 18, Addrs: 北京, StepNum: 180
Name: 李磊, Age: 17, Addrs: , StepNum: 0

===========================

Name: 李明, Age: 20, Addrs: 北京, StepNum: 180
Name: 李磊, Age: 17, Addrs: , StepNum: 170

===========================

李明 say: Hello !!!
Name: 李明, Age: 20, Addrs: 北京, StepNum: 200
Name: 李明, Age: 20, Addrs: 北京, StepNum: 225
30

对于在方法定义是 接受者究竟是使用值还是指针我这里有几点总结

  1. 方法是否会修改接收者本身如果修改则使用指针,如上述addStep()

  2. 观察接收者是否庞大,如巨大的数据库表对象,此时若使用值则可能出现内存浪费

  3. 指针一把梭