阅读 329

Go语言方法(Go语言方法和接收器)

1 方法的定义

Go语言中的方法(Method)是一种作用于特定类型变量的函数。方法是与对象实例绑定的特殊函数。

这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self

::: tip 方法定义语法

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {     //方法体 } 复制代码

  • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母,而不是self、this之类的命名。

  • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。

  • 方法名、参数列表、返回参数:具体格式与函数定义相同。

::: 举例如下

package main import "fmt" type student struct { name string age  int } type dog struct { name string } func (s *student) say(){ fmt.Printf("%s向大家问好\n", s.name) } func main() { //声明一个变量stu var stu student //变量赋值 stu.name="福小林" //调用student类型特定的方法say() stu.say() /*  var d dog d.name="牧羊犬" //此处不能调用say(),报错d.say undefined (type dog has no field or method say) d.say() */ } 复制代码

1.1 指针类型的接收者

指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。这种方式就十分接近于其他语言中面向对象中的this或者self。 例如我们为student添加一个SetAge方法,来修改实例变量的年龄。

//定义一个student的结构体 type student struct { name string age  int } func (s *student) SetAge(){ s.age++ } func main() { //声明一个变量stu var stu student //变量赋值 stu.name="张三" stu.age=18 fmt.Printf("调用SetAge()方法之前%s的年龄%d\n",stu.name,stu.age)  //18 //调用student类型特定的方法调用SetAge() stu.SetAge() fmt.Printf("调用调用SetAge()方法后%s的年龄%d\n",stu.name,stu.age)  //19 } 复制代码

1.2 值类型的接收者

当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。

 type student struct { name string age  int } func (s student) SetAge(){ s.age++ } func main() { //声明一个变量stu var stu student //变量赋值 stu.name="李四" stu.age=30 fmt.Printf("调用SetAge()方法之前%s的年龄%d\n",stu.name,stu.age) //30 //调用student类型特定的方法SetAge() stu.SetAge() fmt.Printf("调用SetAge()方法后%s的年龄%d\n",stu.name,stu.age) //30 } 复制代码

1.3 什么时候使用指针类型接收者

  • 需要修改接收者中的值

  • 接收者是拷贝代价比较大的大对象

  • 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

2 为什么有函数了还需要方法呢

::: tip 原因

  • Go不是纯粹的面向对象编程语言,而且Go不支持类.因此基于类型的方法是一种实现和类相似行为的途径

  • 相同的名字的方法可以定义在不同的类型上,而相同名字的函数是不被允许的。

:::

3 任意类型添加方法

在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。 举个例子,我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后为我们的自定义类型添加方法

//MyInt 将int定义为自定义MyInt类型 type MyInt int //SayHello 为MyInt添加一个SayHello的方法 func (m MyInt) SayHello() { fmt.Println("Hello, 我是一个int。") } func main() { var m1 MyInt m1.SayHello() //Hello, 我是一个int。 m1 = 100 fmt.Printf("%#v  %T\n", m1, m1) //100  main.MyInt } 复制代码

注意:非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法。

4 结构体的“继承”

Go语言中使用结构体也可以模拟实现其他编程语言中面向对象的继承。

package main 复制代码

import "fmt"

//Animal 动物 type Animal struct { name string }

func (a Animal) move() { fmt.Printf("%s会动!\n", a.name) }

//Dog 狗  Dog包裹了Animal 模拟继承了Animal
type Dog struct { Feet    int8 Animal //Animal拥有的方法,Dog也拥有了,因为Dog包裹了Animal,通过嵌套匿名结构体模拟实现继承 }

func (d Dog) wang() { fmt.Printf("%s会汪汪汪~\n", d.name) // d.name相当于 d.Animal.name }

func main() { d1 := Dog{ Feet: 4, Animal: Animal{ name: "旺财", }, } d1.wang() //旺财会汪汪汪~ d1.move() //旺财会动! }

  ## 函数和方法的区别 ::: danger 函数和方法的区别 1、普通函数:接收者(函数参数)为值类型时,不能将指针类型的数据直接传递,反之亦然。 ```go func function_name([parameter list]) [return_types] { /*函数体*/ } 复制代码

2、方法(如struct方法): 接收者为值类型时,可以直接用指针类型的变量调用方法,反之亦然。

func (variable_name variable_data_type) function_name() [return_type]{    /* 方法体*/ } 复制代码

:::

::: tip

  • 方法与函数的区别是,函数不属于任何类型,方法属于特定的类型

  • 方法是与对象实例绑定的特殊函数。

  • 用于维护和展示对象自身的状态。对象是内敛的。普通函数则专注与算法流程,通过接受参数来完成特定的逻辑运算,并返回最终结果,方法是有关联状态的,函数通常是没有的。

  • 方法和函数定义语法区别在于前者实例接受参数,编译器以此确定方法所属的类型。在一些语言中尽管没有定义,但是函数使用了隐式的传递this实例参数。

:::


作者:ourlang
链接:https://juejin.cn/post/7028768858294976543


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐