Go语言之函数基础
一、什么是函数
为完成某一功能的程序指令(语句)的集合,称为函数。在Go中函数分为自定义函数、系统函数。
函数的基本语法:
func 函数名称(形参列表) (返回值列表) { 函数体... return 返回值列表 }
- 形参列表 表示函数的输入
- 函数体 表示为了实现某一功能的的代码块
- 返回值列表 函数可以没有返回值、一个返回值、多个返回值
package main import "fmt" func cal(n1 float64, n2 float64, operator byte) float64 { var res float64 switch operator { case '+': res = n1 + n2 case '-': res = n1 - n2 case '*': res = n1 * n2 case '/': res = n1 / n2 default: fmt.Println("...") } return res } func main() { res := cal(3.25, 2.16, '+') //调用函数 fmt.Println("res=", res) }
二、变量作用域
函数中必定涉及到一些变量,而掌握变量的作用域有利于避免代码出错。
- 函数内部声明的变量叫做局部变量,作用域仅限于函数内部
- 函数外部声明的变量叫做全部变量,作用域在当前整个包都有效,如果其首字母为大写,则作用域在整个程序都有效(任何包中)
- 如果变量是在一个代码块中,如,for/if中,那么这个变量的作用域就在该段代码块
实例:
1、局部变量
package main import "fmt" func test() { // username和Age的作用域只在test函数内部 username := "zhangsan" Age := 20 } func main() { }
2、全局变量
package main import "fmt" // 定义初始化全局变量,该包中所有函数都可以使用,其中Age首字母大写,其它包也可以使用 /* 这里不能写成 username := "zhangsan" 和 Age := 20 因为等价于: var username string username = "zhangsan" 但是第二句的赋值语句不能再函数体外,所以是错误的 */ var username string = "zhangsan" var Age int = 20 func test() { fmt.Println("username",username) fmt.Println("Age",Age) } func main() { test() fmt.Println("main username",username) fmt.Println("main Age",Age) }
3、代码块变量
package main import "fmt" func main() { // 此时变量i的作用域就是在代码块中 for i := 0; i < 5; i++ { fmt.Println(i) } // 如果需要使用这个i变量可以定义成局部变量 var i int for i = 0; i < 5; i++ { fmt.Println(i) } }
三、函数参数传递方式
函数传递的参数方式有:
- 值传递
- 引用传递
无论是值传递还是引用传递,传递给函数的都是变量的副本,不同的是值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝的效率高,因为数据量小。
1、值类型和引用类型
值类型:基本数据类型int系列、float系列、bool、string、数组、struct结构体
引用类型:指针、slice切片、map、管道chan、interface等
值类型默认是值传递,变量直接存储值,内存通常再栈中分配:
引用类型默认是引用传递,变量存储的是一个地址,这个地址对应的空间才真正存储数值,内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就会成为一个垃圾,由GC来回收。
如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量。
package main import "fmt" func test(number *int) { *number = 20 //修改number的值 } func main() { number := 12 test(&number) // 调用变量的值的函数 fmt.Println("main...", number) // main... 20 }
四、注意事项
- 函数的形参列表可以是多个,返回值列表也可以是多个
- 形参列表和返回值列表的数据类型可以是值类型和引用类型
- 函数的命名遵循标识符命名规范,首字母不能是数字,首字母大写该函数可以被本地文件和其它文件使用,类似public,首字母小写,只能被本包文件使用,其它包文件不能使用,类似private
- 函数中的变量是局部,函数外不生效
- 基本数据类型和数组默认都是值传递的,即进行值拷贝,在函数内修改,不会影响到原来的值
- 如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量
- Go函数不支持函数重载(test1(n1 int)、test2(n1 int, n2 int) 这样会包函数重复定义)
- 在Go中,函数也是一种数据类型,可以赋值给一个变量,可以通过变量对函数调用
- 函数是一种数据类型,所以可以作为形参
- Go中支持自定义数据类型(通过 type 自定义数据类型名 数据类型,如:type myInt int,这时myInt就等价int来使用,可以通过 var num myInt来使用)
- 支持对函数返回值命名( test(n1 int, n2) sum int {sum = n1+n2 return} )
- 使用"_"标识符,忽略返回值
- Go函数支持可变参数( 支持0到多个参数:func test(args... int){} ,支持1到多个参数:func test(n1 int, args... int){}。可以使用slice切片 args[index]取值)