网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
- 第 7 行,定义了 Insert() 函数,这个函数拥有两个参数,第一个是背包指针(*Bag),第二个是物品 ID(itemid)。
- 第 8 行,用 append() 将 itemid 添加到 Bag 的 items 成员中,模拟往背包添加物品的过程。
- 第 12 行,创建背包实例 bag。
- 第 13 行,调用 Insert() 函数,第一个参数放入背包,第二个参数放入物品 ID。
Insert() 函数将 *Bag 参数放在第一位,强调 Insert 会操作 *Bag 结构体,但实际使用中,并不是每个人都会习惯将操作对象放在首位,一定程度上让代码失去一些范式和描述性。同时,Insert() 函数也与 Bag 没有任何归属概念,随着类似 Insert() 的函数越来越多,面向过程的代码描述对象方法概念会越来越麻烦和难以理解。
3.1.2 Go语言的结构体方法
将背包及放入背包的物品中使用Go语言的结构体和方法方式编写,为 *Bag 创建一个方法,代码如下:
package main
type Bag struct {
items []int
}
func (b \*Bag) Insert(itemId int) {
b.items = append(b.items, itemId)
}
func main() {
bag := new(Bag)
bag.Insert(1001)
}
第 7 行中,Insert(itemid int) 的写法与函数一致,(b*Bag) 表示接收器,即 Insert 作用的对象实例。
第 13 行中,在 Insert() 转换为方法后,我们就可以愉快地像其他语言一样,用面向对象的方法来调用 b 的 Insert。
每个方法只能有一个接收器,如下图所示。
3.2 接收器——方法作用的目标
接收器的格式如下:
func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {
函数体
}
对各部分的说明:
- 接收器变量:接收器中的参数变量名在命名时,官方建议使用接收器类型名的第一个小写字母,而不是 self、this 之类的命名。例如,Socket 类型的接收器变量应该命名为 s,Connector 类型的接收器变量应该命名为 c 等。
- 接收器类型:接收器类型和参数类似,可以是指针类型和非指针类型。
- 方法名、参数列表、返回参数:格式与函数定义一致。
接收器根据接收器的类型可以分为指针接收器
、非指针接收器
,两种接收器在使用时会产生不同的效果,根据效果的不同,两种接收器会被用于不同性能和功能要求的代码中。
3.2.1 理解指针类型的接收器
指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的 this 或者 self。
由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的
。
在下面的例子,使用结构体定义一个属性(Property),为属性添加 SetValue() 方法以封装设置属性的过程,通过属性的 Value() 方法可以重新获得属性的数值,使用属性时,通过 SetValue() 方法的调用,可以达成修改属性值的效果。
package main
import "fmt"
// 定义属性结构
type Property struct {
value int // 属性值
}
// 设置属性值
func (p \*Property) SetValue(v int) {
// 修改p的成员变量
p.value = v
}
// 取属性值
func (p \*Property) Value() int {
return p.value
}
func main() {
// 实例化属性
p := new(Property)
// 设置值
p.SetValue(100)
// 打印值
fmt.Println(p.Value())
}
运行程序,输出如下:
100
代码说明如下:
- 第 6 行,定义一个属性结构,拥有一个整型的成员变量。
- 第 11 行,定义属性值的方法。设置属性值方法的接收器类型为指针,因此可以修改成员值,即便退出方法,也有效。
- 第 17 行,定义获取值的方法。
- 第 22 行,实例化属性结构。
- 第 24 行,设置值,此时成员变量变为 100。
- 第 26 行,获取成员变量。
3.2.2 理解非指针类型的接收器
当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份,在非指针接收器的方法中可以获取接收器的成员值,但修改后无效
。
点(Point)使用结构体描述时,为点添加 Add() 方法,这个方法不能修改 Point 的成员 X、Y 变量,而是在计算后返回新的 Point 对象,Point 属于小内存对象,在函数返回值的复制过程中可以极大地提高代码运行效率,详细过程请参考下面的代码。
package main
import (
"fmt"
)
// 定义点结构
type Point struct {
X int
Y int
}
// 非指针接收器的加方法
func (p Point) Add(other Point) Point {
// 成员值与参数相加后返回新的结构
return Point{p.X + other.X, p.Y + other.Y}
}
func main() {
// 初始化点
p1 := Point{1, 1}
p2 := Point{2, 2}
// 与另外一个点相加
result := p1.Add(p2)
// 输出结果
fmt.Println(result)
}
代码输出如下:
{3 3}
代码说明如下:
- 第 8 行,定义一个点结构,拥有 X 和 Y 两个整型分量。
- 第 14 行,为 Point 结构定义一个 Add() 方法,传入和返回都是点的结构,可以方便地实现多个点连续相加的效果,例如P4 := P1.Add( P2 ).Add( P3 )
- 第 20 和 21 行,初始化两个点 p1 和 p2。
- 第 23 行,将 p1 和 p2 相加后返回结果。
- 第 25 行,打印结果。
由于例子中使用了非指针接收器,Add() 方法变得类似于只读的方法,Add() 方法内部不会对成员进行任何修改。
3.2.3 指针和非指针接收器的使用
在计算机中,小对象由于值复制时的速度较快,所以适合使用非指针接收器,大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针。
4 为任意类型添加方法
在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。 举个例子,我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后为我们的自定义类型添加方法。
![img](https://img-blog.csdnimg.cn/img_convert/29682a3509f360204f1534a292fb83b5.png)
![img](https://img-blog.csdnimg.cn/img_convert/75af3619462c6b33b7aa913c3a3f34a3.png)
![img](https://img-blog.csdnimg.cn/img_convert/1962686c9927eb6f9631ee9f16a8f3a5.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**
R6q-1715740407889)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**