Golang理解-函数声明
普通函数声明
普通函数的声明形式
func 函数名(参数列表) (返回参数列表) {
函数体
}
参数类型简写
1. 同种类型的返回值
如果返回值是同种类型,则用括号将多个返回值类型括起来,用逗号分隔每个返回值类型
使用return语句时,值列表的顺序需要和函数声明的返回值类型一致
纯类型的返回值对于代码的可读性不是很友好,特别是在同类型的返回值出现时,无法区分每个返回参数的意义
func subAndSum(x, y int) (int, int) {
sub := x - y
sum := x + y
return sub, sum
}
2. 带有变量名的返回值
func namedRetValues() (a, b int) {
a = 1
b = 2
return
}
函数声明时将返回值命名为a,b; 因此可以在函数体中直接对函数的返回值进行赋值. 在命名的返回值方式的函数中,在函数结束前需要显示的使用return语句进行返回
同一种类型返回值和命名返回值两种形式只能二选一,混用时将会发生编译错误;例如:
func namedRetValues() (a, b int, int)
函数调用
函数调用格式: 返回值变量列表 = 函数名(参数列表)
多个返回值列表使用逗号分隔; 例如:
a, b := namedRetValues()
实例:将秒解析为时间单位
package main
// 将秒解析为时间单位
import (
"fmt"
)
const (
// 定义每分钟的秒数
SecondsPerMinute = 60
// 定义每小时的秒数
SecondsPerHour = SecondsPerMinute * 60
// 定义没天的秒数
SecondsPerDay = SecondsPerHour * 24
)
// 将传入的秒解析为3种时间单位
func resolveTime(seconds int) (day, hour, minute int) {
day = seconds / SecondsPerDay
hour = seconds / SecondsPerHour
minute = seconds / SecondsPerMinute
// 显示return返回
return
}
func main() {
// 直接将返回值作为打印参数
fmt.Println(resolveTime(1000))
// 只获取小时和分钟
_, hour, minute := resolveTime(18000)
fmt.Println(hour, minute)
// 只获取天
day, _, _ := resolveTime(90000)
fmt.Println(day)
}
函数参数传递
Go语言中传入和返回参数在调用和返回时都是值传递
这里需要注意的是指针,切片和map等引用类型对象指向的内容在参数传递中不会发生复制,而是将指针进行复制
,类似创建一次引用.
实例: 测试golang中函数参数传递为值传递
; 引用类型参数为一次引用创建
package main
/*
示例: 测试golang中函数参数传递为值传递; 引用类型参数为一次引用创建
*/
import (
"fmt"
)
// 用于测试值传递效果的结构体
type Data struct {
complax []int // 测试切片在参数传递中的效果, 切片是一种动态类型,内部以指针存在
instance InnerData // 实例分配的innerData
ptr *InnerData // 将ptr声明为InnerData的指针类型
}
// 代表各种结构体字段; 声明一个内嵌的结构innerData
type InnerData struct {
a int
}
// 值传递的测试函数;
// 该函数的参数和返回值都是Data类型,在调用中,Data的内存会被复制后传入函数,当函数返回时,又将返回值复制一次,赋值给函数返回值的接收变量
func passByByValue(inFunc Data) Data {
// 输出参数的成员情况
fmt.Printf("in func value: %+v\n", inFunc)
// 打印inFunc的指针
fmt.Printf("in func ptr: %p\n", &inFunc) // 值传递,需要使用&符号取地址; 拥有相同地址且类型相同的变量,表示同一块内存区域
return inFunc // 将传入的变量作为返回值返回,返回的过程中将发生值复制
}
// 测试流程,准备一个Data格式的数据结构并填充所有成员,通过调用测试函数,传入Data结构数据,并获取返回值,对比输入和
// 输出后的Data结构数据变化,特别是指针变化情况以及输入和输出整块数据是否被复制
func main() {
// 准备传入函数的数据结构
in := Data{
complax: []int{1, 2, 3},
instance: InnerData{
5,
},
ptr: &InnerData{1},
}
// 输入结构的成员情况
fmt.Printf("in value: %+v\n", in)
// 输入结构的指针地址
fmt.Printf("in ptr: %p\n", &in)
// 传入结构体,返回同类型的结构体
out := passByByValue(in)
// 输出结构的成员情况
fmt.Printf("out value: %+v\n", out)
// 输出结构的指针地址
fmt.Printf("out ptr: %p\n", &out)
}
总结
- 所有的Data结构的指针地址发生了变化,意味着所有结构都是一块新的内存,无论是将Data结构传入函数内部,还是通过返回值传回Data都会发生复制行为
- 所有的Data结构中的成员值都没有发生变化,原值传递,意味着所有参数都是值传递
- Data结构的ptr成员在传递过程中保持一致,表示指针在函数参数值传递中传递的只是指针值,不会复制指针指向的部分