go语言学习笔记 — 基础 — 复合数据类型 — 结构体:结构体方法(行为)
Posted Locutus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言学习笔记 — 基础 — 复合数据类型 — 结构体:结构体方法(行为)相关的知识,希望对你有一定的参考价值。
go中的方法是一种作用于特定类型变量(也即接收器receiver)的函数。如果把特定类型理解为结构体或类时,接收器receiver类似于python中的self。
在go中,接收器receiver可以是任何类型和结构体;任何类型都可以拥有方法。
在面向对象编程范式中,类拥有的方法一般理解为类可以做的事情。go中的方法也是这个意思。在go中,方法的作用对象是接收器(也即类型实例),而函数没有作用对象。
1. 接收器 —— 方法的作用对象
- 接收器格式
func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {
函数体
}
接收器变量:建议使用接收器类型名的第一个小写字母,而不是self、this。例如Socket类型接收器变量应该命令为s,Connector类型接收器变量命名为c。
接收器类型:与参数类似,可以是指针类型和非指针类型。
方法名、参数列表、返回参数:格式与函数定义一致。
根据类型,接收器可分为指针接收器、非指针接收器。两种接收器会有不同的使用效果。
- 指针类型接收器(常用)
指针类型的接收器由一个结构体指针组成,更接近面向对象中的this或self。
由于指针特性,调用方法时,修改接收器指针任意成员变量,方法结束后,修改都是有效记忆的。
package main
import "fmt"
// 定义结构体Property
type Property struct {
value int // 拥有一个整型的成员变量
}
// 定义修改字段值的方法
func (p *Property) SetValue(v int) {
p.value = v // 没有返回值,就没有返回类型
}
// 定义获取字段值的方法
func (p *Property) GetValue() int {
return p.value
}
func main() {
p := new(Property) //实例化Property结构体,得到结构体指针类型*T
p.SetValue(100) // 调用Setvalue方法,修改属性值
fmt.Println(p.GetValue()) // 调用Getvalue方法,获取属性值
}
- 非指针类型接收器
当方法作用于非指针类型接收器时,go会在代码运行时把接收器的值复制一份。在非指针类型接收器的方法中,我们可以获取接收器的成员值,但修改后无效。
Point为小内存对象,在函数返回值复制时,可以极大提高代码运行效率。
package main
import (
"fmt"
)
// 定义点结构体,包含x,y两个分量
type Point struct {
X int
Y int
}
// 为结构体Point定义一个Add方法,传入和传出都是Point结构体,实现多点连续相加,如p1.Add(p2).Add(p3)
func (p Point) Add(other Point) Point {
return Point{p.X + other.X, p.Y + other.Y}
}
func main() {
p1 := Point{1, 1} // 初始化两个点p1,p2
p2 := Point{2, 2}
result := p1.Add(p2) // 两点相加
fmt.Println(result) // 输出结果
}
在计算机中,小内存对象由于值复制时的速度较快,所以适合使用非指针类型接收器;大内存对象因为值复制性能较差,适合使用指针类型接收器,在接收器和参数间传递时,不进行值复制,而只是传递指针。
2. 为结构体类型添加(绑定)方法
把背包作为“对象”,把物品放入背包的过程作为“方法”。
- 面向过程编程实现
面向过程没有“方法”,只能通过结构体和函数,使用函数入参和函数调用,模拟“方法”。
type Bag struct {
items []int
}
// 定义函数Insert,把一个物品放入背包
func Insert(b *Bag, itemid int) {//背包指针*Bag,物品ID(itemid)
b.items = append(b.items, itemid)// 使用append把物品ID加到Bag的items成员变量,模拟向背包加东西
}
func main() {
bag := new(Bag) // 创建Bag实例bag,得到结构体指针类型*Bag
Insert(bag, 1001) // 调用Insert函数,入参bag,1001
}
Insert()函数把*
Bag类型的参数放在首位,*
Bag结构体为操作对象。
- 面向对象编程实现
把背包和放入物品到背包中的过程,使用结构体和方法实现。
type Bag struct {
items []int
}
// 为Bag类型添加Insert方法
func (b *Bag) Insert(itemid int) {
b.items = append(b.items, itemid)
}
func main() {
b := new(Bag) // 实例化结构体Bag,得到*Bag类型的b
b.Insert(1001) // 对操作对象b,调用方法Insert
}
定义方法Insert,作用对象是接收器(b *Bag)。每个方法只能有一个接收器,func (b *Bag) Insert(itemid int)
中,(b *Bag)是方法Insert的接收器,为结构体添加方法。
3. 为任何类型添加方法
go可以为任何类型添加方法。给类型添加方法,就像给结构体添加方法一样,因为结构体也是一种类型。
- 为基本类型添加方法
go使用type关键字定义新的自定义类型,之后就可以给自定义类型添加各种方法。
判断一个值是否为0,下面给出面向过程和面向对象两种方式:
if v == 0 {
express // v等于0
}
if v.IsZero() { // 把v作为整型对象,可以增加一个IsZero方法
express // v等于0
}
package main
import "fmt"
// 自定义类型MyInt
type MyInt int
// 为Myint类型添加IsZero方法,(m MyInt)为非指针接收器,数值类型没有必要使用指针接收器
func (m MyInt) IsZero() bool {
return m == 0
}
// 为MyInt类型添加Add()方法
func (m MyInt) Add(other int) int {
return other + int(m) // 把m从MyInt类型转换成int类型
}
func main() {
var b MyInt
fmt.Println(b.IsZero()) // 调用b的IsZero方法,由于使用非指针接收器,b的值会被复制到IsZero方法进行判断
b = 1
fmt.Println(b.Add(2)) // 调用b的Add方法
}
// true
// 3
以上是关于go语言学习笔记 — 基础 — 复合数据类型 — 结构体:结构体方法(行为)的主要内容,如果未能解决你的问题,请参考以下文章
go语言学习笔记 — 基础 — 复合数据类型 — 结构体:使用匿名结构体分离json数据
go语言学习笔记 — 基础 — 复合数据类型 — 结构体:如何在包中引用另外一个包的结构体?
go语言学习笔记 — 基础 — 复合数据类型 — 结构体:类型内嵌与结构体内嵌(扩展和复用)
go语言学习笔记 — 基础 — 复合数据类型 — 结构体:构造函数 — 封装结构体和类型的一系列初始化操作(封装数据)