【一Go到底】第二十二天---函数参数传递方式、变量作用域

125 阅读3分钟

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

一、函数参数传递方式

1.1 传递方式(2种)

  1. 值传递(值类型参数)

  2. 引用传递(引用类型参数)

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

1.2 值类型和引用类型

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

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

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

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

  3. 如果希望函数内的变量能够修改函数外的变量的值,可以传入变量的地址&,函数内以指针的方式操作变量。效果上类似于引用

二、变量作用域

2.1 变量作用域说明

  1. 函数内部声明/定义的变量叫局部变量,作用域仅限于函数内部。详见函数内部变量案例
  2. 函数外部声明/定义的变量叫全局变量,作用域在整个包都有效,如果其首字母为大写,则作用域在整个程序有效。
  3. 如果变量是在一个代码块,如 for/if中,那么这个变量的作用域仅在该代码块

2.2 案例演示

2.2.1 函数内部变量案例

package main

import "fmt"

// 函数
func test() {
	// 下面声明的变量 仅在该函数内,与首字母是否大小写无关
	// 注意 := 的声明方式,仅在函数内可以这样声明
	// 在函数内声明的变量 仅在该函数内操作,在函数体外无法使用
	age := 10
	Name := "Test"
	fmt.Printf("Func inside use , age=%v, Name=%v", age, Name)
}

func main() {
	test()
	// // 下面调用会报错
	// fmt.Println(age,Name)
}

2.2.2 函数外部声明案例

在其他文件也可以引用(大写字母开头)

package main

import "fmt"

var Age int = 18
var Name string = "Mike"

func main() {
	// Age = 18, Name = Mike
	fmt.Printf("Age = %v, Name = %v", Age, Name)
}

2.3 作用域案例练习

// package main

// import "fmt"

// // 函数
// func test() {
// 	// 下面声明的变量 仅在该函数内,与首字母是否大小写无关
// 	// 注意 := 的声明方式,仅在函数内可以这样声明
// 	// 在函数内声明的变量 仅在该函数内操作,在函数体外无法使用
// 	age := 10
// 	Name := "Test"
// 	fmt.Printf("Func inside use , age=%v, Name=%v", age, Name)
// }

// func main() {
// 	test()
// 	// // 下面调用会报错
// 	// fmt.Println(age,Name)
// }

// // 函数外部定义变量使用

// package main

// import "fmt"

// var Age int = 18
// var Name string = "Mike"

// func main() {
// 	// Age = 18, Name = Mike
// 	fmt.Printf("Age = %v, Name = %v", Age, Name)
// }

// 作用域案例练习

package main

import "fmt"

var name = "June"

func test01() {
	fmt.Println(name)
}

func test02() { // 编译器采用就近原则
	name := "MK"
	fmt.Println(name)
}

func main() {
	fmt.Println(name) // 输出 June
	test01()          // 输出June
	test02()          // 输出 MK
	test01()          // 输出 June
}


三、函数练习

3.1 打印金字塔

根据用户输入,打印对应层数的金字塔

package main

import "fmt"

func tower(layers int) {
	for i := 1; i <= layers; i++ {
		// 打印空格
		for k := 1; k <= layers-i; k++ {
			fmt.Print(" ")
		}
		for j := 1; j <= 2*i-1; j++ {
			// // 空心金字塔
			// if j == 1 || j == 2*i-1 || i == layers {
			// 	fmt.Print("*")
			// } else {
			// 	fmt.Print(" ")
			// }

			fmt.Print("*")
		}
		fmt.Println()

	}
}

func main() {

	var layers int
	fmt.Printf("请输入您要打印的层数:")
	fmt.Scanln(&layers)

	tower(layers)
}

3.2 打印九九乘法表

package main

import "fmt"

func nMn(num int) {
	for i := 1; i <= num; i++ {
		for j := 1; j <= i; j++ {
			fmt.Printf("%v * %v = %v \t", j, i, j*i)
		}
		fmt.Println()
	}

}

func main() {

	var num int
	fmt.Printf("请输入一个整数(1-9): ")
	fmt.Scanln(&num)

	nMn(num)
}