go【第三篇】函数
函数定义和使用
go的函数也是一等对象
在Go语言中,函数的基本组成为:关键字func、函数名、参数列表、返回值、函数体和返回语句
package main // 规范:包名和入口函数必须是main import ( "fmt" ) //无参数无返回值 func Add() { fmt.Println(666) } //无参数有返回值 func Add2() (a int){ return 999 } //有参数无返回值 func Add3(a int, b int) { fmt.Println(a, b) } //有参数有返回值 func Add4(a int, b int) (sum int) { return a + b // 支持多重返回值 } /*return 另一种写法 func Add4(a int, b int) (sum int) { sum = a + b return // 支持多重返回值 } */ //多个返回值 //写法一 //func Add5(a int, b int) (c,d int) { // return a, b // 支持多重返回值 //} //写法二(官方推荐写法) func Add5(a int, b int) (c int,d int) { return a, b // 支持多重返回值 } //写法三 //func Add5(a int, b int) (int, int) { // return a, b // 支持多重返回值 //} func main() { Add() //无参数无返回值 fmt.Println(Add2()) //无参数有返回值 Add3(1, 2) sum := Add4(1, 2) fmt.Println(sum) fmt.Println(Add5(1, 2)) } /*输出 2 2 */
变量作用域
函数外的每个语句都必须以关键字开始(var
, func
等等),因此 :=
结构不能在函数外使用。
没有明确初始值的变量声明会被赋予默认值(0 false "" nil等)
局部变量
package main //必须 import "fmt" func test() { a := 10 fmt.Println("a = ", a) } func main() { //定义在{}里面的变量就是局部变量,只能在{}里面有效 //执行到定义变量那句话,才开始分配空间,离开作用域自动释放 //作用域,变量其作用的范围 //a = 111 { i := 10 fmt.Println("i = ", i) } //i = 111 if flag := 3; flag == 3 { //flag不在{}内丹属于if块,依然是局部变量 fmt.Println("flag = ", flag) } flag = 4 }
全局变量
package main //必须 import "fmt" func test() { fmt.Println("test a = ", a) } //定义在函数外部的变量是全局变量 //全局变量在任何地方都能使用 var a int func main() { a = 10 fmt.Println("a = ", a) test() }
变量重名
package main //必须 import "fmt" var a byte //全局变量 func main() { var a int //局部变量 //1、不同作用域,允许定义同名变量 //2、使用变量的原则,就近原则 fmt.Printf("%T\n", a) //int { var a float32 fmt.Printf("2: %T\n", a) //float32 } test() } func test() { fmt.Printf("3: %T\n", a) //uint8, 就是byte }
函数参数
Go没有默认参数和位置参数
不定参数
类似python的冗余参数
不定参数是指函数传入的参数个数为不定数量 ,...type必须是最后一个参数,args把参数封装成数组
同一类型的不定参数
package main import "fmt" func main() { myfunc(1,2) } func myfunc(args ...int) { fmt.Println(args) for _, arg := range args { fmt.Println(arg) } } ####### [1 2]
任意类型的不定参数
package main import "fmt" func MyPrintf(args ...interface{}) { fmt.Println(args) for _, arg := range args { switch arg.(type) { case int: fmt.Println(arg, "is an int value.") case string: fmt.Println(arg, "is a string value.") case int64: fmt.Println(arg, "is an int64 value.") default: fmt.Println(arg, "is an unknown type.") } } } func main() { var v1 int = 1 var v2 int64 = 234 var v3 string = "hello" var v4 float32 = 1.234 MyPrintf(v1, v2, v3, v4) } ################# [1 234 hello 1.234] is an int value. is an int64 value. hello is a string value. 1.234 is an unknown type.
内建函数
函数类型
package main //必须 import "fmt" func Add(a, b int) int { return a + b } func Minus(a, b int) int { return a - b } //函数也是一种数据类型, 通过type给一个函数类型起名 //FuncType它是一个函数类型 type FuncType func(int, int) int //没有函数名字,没有{} func main() { var result int result = Add(1, 1) //传统调用方式 fmt.Println("result = ", result) //声明一个函数类型的变量,变量名叫fTest var fTest FuncType fTest = Add //是变量就可以赋值 result = fTest(10, 20) //等价于Add(10, 20) fmt.Println("result2 = ", result) fTest = Minus result = fTest(10, 5) //等价于Minus(10, 5) fmt.Println("result3 = ", result) } /*输出 result = 2 result2 = 30 result3 = 5 */
package main //必须 import "fmt" type FuncType func(int, int) int //实现加法 func Add(a, b int) int { return a + b } func Minus(a, b int) int { return a - b } func Mul(a, b int) int { return a * b } //回调函数,函数有一个参数是函数类型,这个函数就是回调函数 //计算器,可以进行四则运算 //多态,多种形态,调用同一个接口,不同的表现,可以实现不同表现,加减乘除 //现有想法,后面再实现功能 func Calc(a, b int, fTest FuncType) (result int) { fmt.Println("Calc") result = fTest(a, b) //这个函数还没有实现 //result = Add(a, b) //Add()必须先定义后,才能调用 return } func main() { a := Calc(1, 1, Mul) fmt.Println("a = ", a) } /* Calc a = 1 */
匿名函数
package main //必须 import "fmt" func main() { a := 10 str := "mike" //匿名函数,没有函数名字, 函数定义,还没有调用 f1 := func() { //:= 自动推导类型 fmt.Println("a = ", a) fmt.Println("str = ", str) } f1() //给一个函数类型起别名 type FuncType func() //函数没有参数,没有返回值 //声明变量 var f2 FuncType f2 = f1 f2() //定义匿名函数,同时调用 func() { fmt.Printf("a = %d, str = %s\n", a, str) }() //后面的()代表调用此匿名函数 //带参数的匿名函数 f3 := func(i, j int) { fmt.Printf("i = %d, j = %d\n", i, j) } f3(1, 2) //定义匿名函数,同时调用 func(i, j int) { fmt.Printf("i = %d, j = %d\n", i, j) }(10, 20) //匿名函数,有参有返回值 x, y := func(i, j int) (max, min int) { if i > j { max = i min = j } else { max = j min = i } return }(10, 20) fmt.Printf("x = %d, y = %d\n", x, y) }
闭包
情况一
package main //必须 import "fmt" func main() { a := 10 str := "mike" func() { //闭包以引用方式捕获外部变量 a = 666 str = "go" fmt.Printf("内部:a = %d, str = %s\n", a, str) }() //()代表直接调用 fmt.Printf("外部:a = %d, str = %s\n", a, str) }
情况二
package main //必须 import "fmt" //函数的返回值是一个匿名函数,返回一个函数类型 func test02() func() int { var x int //没有初始化,值为0 return func() int { x++ return x * x } } func main() { //返回值为一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数,f来调用闭包函数 //它不关心这些捕获了的变量和常量是否已经超出了作用域 //所以只有闭包还在使用它,这些变量就还会存在。 f := test02() fmt.Println(f()) //1 fmt.Println(f()) //4 fmt.Println(f()) //9 fmt.Println(f()) //16 fmt.Println(f()) //25
defer
defer语句在函数结束时执行
如果代码哪部分有异常,defer代码依然执行
package main //必须 import "fmt" func main() { //defer延迟调用,main函数结束前调用 defer fmt.Println("bbbbbbbbbbbbb") fmt.Println("aaaaaaaaaaaaaaa") } /* aaaaaaaaaaaaaaa bbbbbbbbbbbbb */
多个defer
package main //必须 import "fmt" func test(x int) { result := 100 / x fmt.Println("result = ", result) } func main() { defer fmt.Println("aaaaaaaaaaaaaa") defer fmt.Println("bbbbbbbbbbbbbb") //调用一个函数,导致内存出问题 defer test(0) defer fmt.Println("ccccccccccccccc") } /* ccccccccccccccc bbbbbbbbbbbbbb aaaaaaaaaaaaaa */
package main //必须 import "fmt" func test(x int) { result := 100 / x fmt.Println("result = ", result) } func main() { defer fmt.Println("aaaaaaaaaaaaaa") defer fmt.Println("bbbbbbbbbbbbbb") //调用一个函数,导致内存出问题 test(0) defer fmt.Println("ccccccccccccccc") } /* bbbbbbbbbbbbbb aaaaaaaaaaaaaa */
谢谢