Go笔记:方法
Posted 无虑的小猪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go笔记:方法相关的知识,希望对你有一定的参考价值。
Go语言没有Java语言面向对象的特性,也无类对象的概念。但可以使用结构体实现这些特性。
1、方法的声明
Go中的方法是一种特殊的函数,与struct相关联,被称为struct的接收者。可以理解为方法就是有接收者的函数。语法格式如下:
type mystruct struct func (recv mystruct) my_method(para) return_type func (recv *mystruct) my_method(para) return_type
mystruct:定义的结构体
recv :接受该方法的结构体
my_method:方法名称
para:方法参数列表
return_type:方法返回值类型
示例代码如下:
package main import "fmt" // 结构体 type Book struct bookName string // 方法 // 比函数多了一个接受者,接受者为结构体 func (bk Book) info(name string) bool fmt.Printf("book.bookName:%v is very good\\n", bk.bookName) return true; func main() book := Book"平凡的世界" book.info(book.bookName)
2、接收者类型
接收者类型有值类型和指针类型。区别在于接收者是否需要复制结构体副本。值类型复制副本,指针类型不复制副本。
2.1、值类型
以接收者是结构体为例,值类型示例代码如下:
package main import "fmt" // 结构体 type Book struct bookName string // 比函数多了一个接受者,接受者为结构体,值类型接受者 func (bk Book) valueType() bk.bookName = bk.bookName + " valueType" func main() bk := Book"平凡的世界" // 值作为接受者 bk.valueType() fmt.Printf("valueType: %v\\n", bk)
2.2、指针类型
以接收者是结构体为例,指针类型示例代码如下:
package main import "fmt" // 结构体 type Book struct bookName string // 比函数多了一个接受者,接受者为结构体,指针类型接受者 func (bk *Book) pointerType() bk.bookName = bk.bookName + " pointerType" func main() bk := Book"平凡的世界" // 指针作为接受者 bk.pointerType() fmt.Printf("pointerType: %v\\n", bk)
3、实现OOP的属性和方法
Go语言无面向对象的概念,也无封装的概念,但可通过结构体struct和方法来实现OOP的属性和方法等特性。
package main import "fmt" // 结构体 等价于 对象 ; name 等价于 属性 type Person struct name string // receiver 接收者方法 等价于 方法 func (per Person) eat() fmt.Printf("run method: %v eat \\n", per.name) func main() // 等价于Java中的 new 对象 per := Person"zs" // 输出属性 fmt.Printf("per.name: %v\\n", per.name) // 执行方法 per.eat()
4、方法的注意事项
1、struct结合其方法等价于面向对象的方法。struct可以与其方法分开,并非一定同属一个文件,但必须同属一个包;
2、方法两种接收类型:(T type)和(T *type);
3、方法就是函数,Go中无方法重载的概念,所以在Go中所用方法名必须唯一;
4、若receiver是一个指针类型,则会自动解除引用;
5、方法和type分开,表示实例的行为与数据存储是分开的,是通过receiver建立的关联关系。
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语言学习笔记 — 基础 — 复合数据类型 — 结构体:结构体方法(行为)
《Go语言精进之路,从新手到高手的编程思想方法和技巧1》读书笔记和分享