Go学习笔记(12)Go方法Method

x33g5p2x  于2022-03-06 转载在 其他  
字(2.0k)|赞(0)|评价(0)|浏览(228)

Go的方法Method

在面向对象的语言中,类可以包括属性和方法;而在Go中,并无类的概念,往往使用结构体struct来替代类的操作,但结构体中只有字段属性,那方法在哪里?
    Go为我们提供了一种名为Method的特殊函数,它通过作用在某个接收者上面来实现与其关联,可以实现类的方法这一需求。

  • Go的方法是一种特殊的函数,与普通函数的区别在于,方法需要一个接收者(receiver),它是作用在接收者上的函数,接收者是某种类型的变量
  • 接收者几乎可以是任何的类型,不仅仅是结构体struct,还可以是整型、浮点型、布尔型、数组等等,但是不能是接口。因为接口是一个抽象定义,但是方法却是具体实现;使用接口作接收者会引发一个编译错误:invalid receiver type
  • 使用结构体加上它的方法其实就类似实现了面向语言中的类,但不同的是,Go拓展了“类”的范围,Go的方法可以在任何类型上面添加,不局限于结构体
  • 在Go中,类型的代码和绑定在它上面的代码可以分开存在于不同的源文件中,不一定要放置在一起。但至少,它们必须是同一个包的(如果方法和接收者类型在不同包,方法会找不到他的接收者)。在同一个包中,方法可以访问到类型中的属性字段(无论是否大写)
  • 方法是一种函数,因此不支持重载,即对于某个类型,不能有多个相同名字的方法。但是,如果接收者类型不同,那么允许相同名字的方法存在,即相同名字的方法可以在多个不同的类型接收者上存在。如下
func (a int) add(b int) int {return a + b}
func (a float32) add(b float32) float32 {return a+b}

方法的定义及使用

Go方法定义的格式

func (recv receiver_type) methodName(parameter_list) (return_value_list) {
	...
}

下面是一个方法使用的实例,我们在结构体student上面添加上方法Study。在方法定义的第一个括号中指定接收者变量

type student struct {
    name string
    id   int
}
func main(){
    s := student{
        name : "xiao",
        id : 1,
    }
    s.Study()
}
func (a student) Study(){
    fmt.Println(a.name, "is studying")
}

上面是对结构体添加方法,我们还可以结合类型别名对其它任意类型来添加方法

type zhengxing int
func main(){
	var a zhengxing
	a.Print()
}
func (i zhengxing) Print(){
	fmt.Println("zhengxing")
}

在上面的代码中,我们在主程序中调用方法都是先创建某个类型的变量,然后通过变量来调用方法,这种方式称之为Method Value,还有另外一种调用方法的方法,称之为Method Expression,它是通过类型来调用方法,并将类型的变量作为参数传递到方法中:

type zhengxing int
func main(){
	var a zhengxing
	zhengxing.Print(a)
}
func (i zhengxing) Print(){
	fmt.Println("zhengxing")
}

方法接收者的值传递与指针传递

方法中对接收者默认也是值传递,即传入方法的接收者为原始接收者的拷贝,在方法中无法直接改变真正的接收者变量。如果确实需要在方法中改变接收者,可以使用接收者的指针来传递:

type student struct {
    name string
    id   int
}
func main(){
    s := student{
        name : "xiao",
        id : 1,
    }
    s.changeId(110)
    fmt.Println(s.id)
}
func (a *student) changeId(id int){
    a.id = id
    fmt.Println(a.id)
}

从性能方面考虑,传递一个地址比起拷贝一个类型变量更加具有优势,因此更加推荐这种传递接收者类型的指针。而且我们也可以看到在访问结构体字段时用法和非指针的结构体的用法是相同的,Go在内部帮我们自动作了转换

内嵌方法的继承

之前在上一篇文章中提到了结构体内可以通过内嵌结构体的方式来实现类似于继承内嵌结构体字段的效果,现在我们增加了方法的使用,因此,如果内嵌结构体拥有一个方法,那么外层的结构体同样继承了内嵌结构体的方法,可以直接通过外层结构体直接访问到该方法。而如果外层结构体定义了一个同名的方法,那么外层的方法将覆盖掉内嵌方法,直接通过外层结构体访问该方法将访问到外层结构体关联的方法,而如果要使用内嵌方法,则需要一层一层嵌套访问。
    是不是感觉很熟悉?没错,这个解决方式和字段名冲突时的解决方式是相同的。

相关文章