李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
16.Golang方法和函数区别
Leefs
2022-07-06 AM
1538℃
0条
[TOC] ### 前言 ![16.Golang方法和函数区别01.jpeg](https://lilinchao.com/usr/uploads/2022/07/3927809201.jpeg) 在前面的章节中介绍过了Golang中的方法和函数,但是如果不进行比较,对于两者的认识还是很容易产生混淆。 ### 一、概述 Go语言支持方法。Go方法与Go函数相似,但有一点不同,**方法就是一个包含了接收者参数的函数**。 + **在接收者参数的帮助下,该方法可以访问接收者的属性。** + **接收方可以是结构类型或非结构类型。** + **在代码中创建方法时,接收者和接收者类型必须出现在同一个包中。**而且不允许创建一个方法,其中的接收者类型已经在另一个包中定义,包括像int、string等内建类型。如果您尝试这样做,那么编译器将抛出错误。 **语法** ```go func(reciver_name Type) method_name(parameter_list)(return_type){ // Code } ``` 在此,可以在方法内访问接收器。 **示例** ```go type person struct { name string age int8 } //函数,求和 func sum(x,y int) int { return x + y } //方法 func (p person) String() string{ return fmt.Sprintf("姓名:%s\n年龄:%d",p.name,p.age) } func main() { //初始化并调用方法 p := person{name:"Leefs",age:18} fmt.Println(p.String()) //调用函数 x,y := 10,20 s := sum(x,y) fmt.Printf("sum=%d\n",s) } ``` **运行结果** ``` 姓名:Leefs 年龄:18 sum=30 ``` **总结** **方法在定义的时候,会在`func`和方法名之间增加一个参数,这个参数就是接收者,这样我们定义的这个方法就和接收者绑定在了一起,称之为这个接收者的方法。** ### 二、同名方法 在 Go 中,相同的名字的方法可以定义在不同的类型上,而相同名字的函数是不被允许的。如果在GO语言程序中添加一个同名函数,就会报错。但是在不同的结构体上面定义同名的方法就是可行的。 ```go type person struct { name string age int8 } //同名方法,返回姓名和年龄 func (p person) String() string { return fmt.Sprintf("姓名:%s,年龄:%d",p.name,p.age) } type student struct { name string } //同名方法,返回学生姓名 func (s student) String() string{ return fmt.Sprintf("学生姓名:%s",s.name) } func main() { p := person{name: "Leefs",age: 18} fmt.Println(p.String()) s := student{name: "Jeyoo"} fmt.Println(s.String()) } ``` **运行结果** ``` 姓名:Leefs,年龄:18 学生姓名:Jeyoo ``` ### 三、值传递和引用传递 *该小节在文章《Golang结构体(二)》中已经做了详细介绍* + **值传递**:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 + **引用传递**:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 **示例** ```go type person struct { name string } //值传递 func (p person) changeName(name string){ p.name = name } //引用传递 func (p *person) changeNamePointer(name string){ p.name = name } func main() { p := person{name:"Leefs"} fmt.Printf("原始名称:%s\n",p.name) //修改失败 p.changeName("Took") fmt.Printf("通过值传递修改名称:%s\n",p.name) //修改成功 p.changeNamePointer("Jeyoo") fmt.Printf("通过引用传递修改名称:%s\n",p.name) } ``` **运行结果** ``` 原始名称:Leefs 通过值传递修改名称:Leefs 通过引用传递修改名称:Jeyoo ``` 在调用方法的时候,传递的接收者本质上都是副本,只不过一个是这个值副本,一是指向这个值指针的副本。指针具有指向原有值的特性,所以修改了指针指向的值,也就修改了原有的值。我们可以简单的理解为值接收者使用的是值的副本来调用方法,而指针接收者使用实际的值来调用方法。 ### 四、在方法中使用值接收器与在函数中使用值参数 当一个函数有一个值参数,它只能接受一个值参数。当一个方法有一个值接收器,它可以接受值接收器和指针接收器。 ```go type Lesson struct { Name string } //方法 func (lesson Lesson) PrintInfo() { fmt.Println(lesson.Name) } //函数 func PrintInfo(lesson Lesson) { fmt.Println(lesson.Name) } func main() { lesson := Lesson{"《张宇基础30讲》"} //调用函数 PrintInfo(lesson) //调用方法 lesson.PrintInfo() bPtr := &lesson //调用函数 //PrintInfo(bPtr) // error //调用方法 bPtr.PrintInfo() } ``` 在上面的程序中,使用值参数 `PrintInfo(lesson)` 来调用这个函数是合法的,使用值接收器来调用 `lesson.PrintInfo()` 也是合法的。 然后在程序中我们创建了一个指向 `Lesson` 的指针 `bPtr` ,通过使用指针接收器来调用 `bPtr.PrintInfo()` 是合法的,但使用值参数调用 `PrintInfo(bPtr)` 是非法的。 ### 五、在非结构体上的方法 不仅可以在结构体类型上定义方法,也可以在非结构体类型上定义方法,但是有一个问题。为了在一个类型上定义一个方法,**方法的接收器类型定义和方法的定义应该在同一个包中**。 **示例** ```go package main import "fmt" type myInt int func (a myInt) add(b myInt) myInt { return a + b } func main() { var x myInt = 50 var y myInt = 7 fmt.Println(x.add(y)) // 57 } ``` ### 总结 方法和函数之间的差异: | 方法 | 函数 | | :--------------------------------------- | :--------------------------------------- | | 包含接收器 | 不包含接收器 | | 可以接受指针和值 | 不能同时接受指针和值 | | 可以在程序中定义相同名称但不同类型的方法 | 程序中不允许定义相同名称但不同类型的函数 | *附参考文章链接* *http://www.go-edu.cn/2022/05/20/go-12-%E6%96%B9%E6%B3%95/* *https://www.cainiaojc.com/golang/go-methods.html*
标签:
Golang基础
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2228.html
上一篇
15.Golang流程控制
下一篇
17.Golang接口介绍
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Netty
Linux
工具
JavaWeb
Livy
字符串
nginx
Hadoop
Java工具类
Azkaban
VUE
栈
Spring
哈希表
前端
Nacos
Hive
Git
NIO
Sentinel
散列
链表
Stream流
Tomcat
并发编程
Quartz
机器学习
算法
Http
正则表达式
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭