【第二十三篇】GO函数参数传递方式|变量作用域

101 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

一、函数参数的传递方式:

一、基本介绍:

我们在讲解函数注意事项和使用细节时,已经讲过值引用和引用类型了,这里我们再系统总结一下,因为这是重难点,值类型参数默认就是值传递,而引用类型参数默认就是引用传递。

二、两种传递方式:

  1. 值传递
  2. 引用传递

其实,不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递是地址的拷贝,一般来说,地址拷贝的效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。

两种方式都可以用,引用传递效率高,缺点是如果函数里修改数据了源数据会发生变化。


三、函数参数的传递方式:

值类型和引用类型:

  1. 值类型:基本数据类型int系列、float 系列、bool、string、数组和结构体struct
  2. 引用类型:指针、slice切片、map、管道chan、interface等都是引用类型

值传递和引用传递使用特点:

  1. 值传递默认是值传递,变量直接存储值,内存通常在栈中分配。

  1. 引用类型默认是引用传递,变量存储的是一个地址,这个地址对应的空间才真正存储数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,有GC来回收。

  1. 如果希望函数内的变量能修改函数外的变量(指的是默认以值传递的方式的数据类型),可以传入变量的地址 & ,函数内以指针的方式操作变量。从效果上看类似引用

值传递:传递的是原本的数值

引用传递:传递地址值

*:取值

&:取地址

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)
}


二、变量作用域:

一、说明:

  1. 函数内部声明/定义的变量叫做局部变量,作用域仅限于函数内部。
package main

// 局部变量:
func test() {
	// age 和 Name 的作用域就只在test函数内部
	// 在函数内声明或定义的变量,其作用域只在本函数内
	age := 10
	Name := "tom~"
}
func main() {

}

  1. 函数外部声明/定义的变量叫做全局变量,作用域在整个包都有效,如果其首字母为大写,则作用域在整个程序有效。
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()
}

  1. 如果变量是在一个代码块,比如 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)

}