持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
一、函数参数的传递方式:
一、基本介绍:
我们在讲解函数注意事项和使用细节时,已经讲过值引用和引用类型了,这里我们再系统总结一下,因为这是重难点,值类型参数默认就是值传递,而引用类型参数默认就是引用传递。
二、两种传递方式:
- 值传递
- 引用传递
其实,不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递是地址的拷贝,一般来说,地址拷贝的效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。
两种方式都可以用,引用传递效率高,缺点是如果函数里修改数据了源数据会发生变化。
三、函数参数的传递方式:
值类型和引用类型:
- 值类型:
基本数据类型int系列、float 系列、bool、string、数组和结构体struct - 引用类型:
指针、slice切片、map、管道chan、interface等都是引用类型
值传递和引用传递使用特点:
- 值传递默认是值传递,变量直接存储值,内存通常在栈中分配。
- 引用类型默认是引用传递,变量存储的是一个地址,这个地址对应的空间才真正存储数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,有GC来回收。
- 如果希望函数内的变量能修改函数外的变量(指的是默认以值传递的方式的数据类型),可以传入变量的地址 & ,函数内以指针的方式操作变量。从效果上看类似引用
值传递:传递的是原本的数值
引用传递:传递地址值
*:取值
&:取地址
package main
import "fmt"
// n1 就是 *int 类型
func test03(n1 *int) {
*n1 = *n1 + 10
fmt.Println("test03() n1=", *n1)
}
func main() {
num := 20
test03(&num)
fmt.Println("main() num=", num)
}
二、变量作用域:
一、说明:
- 函数内部声明/定义的变量叫做局部变量,作用域仅限于函数内部。
package main
// 局部变量:
func test() {
// age 和 Name 的作用域就只在test函数内部
// 在函数内声明或定义的变量,其作用域只在本函数内
age := 10
Name := "tom~"
}
func main() {
}
- 函数外部声明/定义的变量叫做全局变量,作用域在整个包都有效,如果其首字母为大写,则作用域在整个程序有效。
package main
import "fmt"
// 定义全局变量
var age int = 50
var Name string = "jack~"
// 局部变量:
func test() {
// age 和 Name 的作用域就只在test函数内部
// 在函数内声明或定义的变量,其作用域只在本函数内
age := 10
Name := "tom~"
fmt.Println("age=", age)
fmt.Println("Name=", Name)
}
func main() {
fmt.Println("age=", age)
fmt.Println("Name=", Name)
test()
}
- 如果变量是在一个代码块,比如 for / if 中,那么这个变量的作用域就在该代码块。
package main
import "fmt"
func main() {
// 如果变量是在一个代码块,比如 for / if 中,那么这个变量的作用域就在该代码块。
for i := 0; i <= 10; i++ {
fmt.Println("i=", i)
}
// 局部变量
var i int
for i := 0; i <= 10; i++ {
fmt.Println("i=", i)
}
fmt.Println("i=", i)
}