2022年8月更文挑战14-golang方法

139 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

golang方法

前文

本文内容为对于golang方法相关知识的总结,主要为个人对于golang方法的理解,其中不免存在不足或不完善之处。

方法声明

golang的函数很明显,就是通过定义一段逻辑功能,具有自己的函数名以及内部的函数逻辑。相对而言,golang方法与函数十分的类似,但区别之处在于golang的方法定义时,需要在函数名称前进行调用对象类型的指定。也就是golang的方法定义时已经规定了可调用对象或指针的类型,而函数并没有。

type Point struct{ X, Y float64 }

// 函数
func Distance(p, q Point) float64 {
    //具体逻辑
}

// 方法
func (p Point) Distance(q Point) float64 {
    //具体逻辑
}

如上面的代码所示,当我们在函数名称前指定了该函数调用方的类型,它也就从函数变成了方法。但有一点需要注意,方法中采用的参数不可以为指针类型的变量,例如p是*int,那么不可以将p直接作为方法的接收器。

基于指针函数的调用

在调用函数时,golang支持值传递和引用传递的双重方式。当我们通过指针进行数据传递时,传递的是原始对象的指针,修改时也是进行原始对象的修改。而当我们采用值传递时,会将原始的对象进行一次复制,形成一个新的对象。那么在方法的调用时也是一样,当我们的对象很大时,一般直接采用指针作为方法定义时的调用方。所以对于同样的一个方法,我们也就有了如下的两种声明方式。

func (p *Point) ScaleBy(factor float64) {
    // 具体逻辑省略
}

func (p Point) ScaleBy(factor float64) {
    // 具体逻辑省略
}

那么在使用的过程中,对于这两种方法的声明方式,golang编译器又进行了一些底层的优化。也就是指针声明的方法可以通过对象直接调用,而对象类型的方法又可以传入指针进行调用。具体的规则如下:

  • 接收器的形参类型和实参类型相同
  • 接受器的形参类型为T,传入的实参类型为*T,编译器会自动找到对应的对象
  • 接收器的形参类型为*T,传入实参为实际对象,注意不能是匿名对象,编译器会自动寻找到穿入实参的地址。

通过嵌入结构体扩展类型

当一个结构体A中包含另一个结构体B时,我们可以把结构体认为是结构体A的基类。这很像java中的类继承,B可以认为是父类。我们可以在结构体A中直接调用结构体B中的所有方法,直接用结构体A进行调用即可。但与java中的继承有所区别的是,不能够将结构体作为结构体B在其他的场景下应用。另外就是当结构体中包含的对象存在多个同名方法时,也会导致该用法的问题,会找不到具体的方法。

后记

  • 千古兴亡多少事?悠悠。不尽长江滚滚流。