go 函数
函数声明和注释
1、函数声明: func 函数名字 (参数列表) [(返回值列表)] {}
func add(a, b int) (int, int) { }
2. 注释,两种注释,单行注释: // 和多行注释 /* */
3、 一个.go文件初始化,先执行全局变量,再执行init()函数,init()函数自动调用
4、多个包引用,如果引用顺序是main -> add -> test,初始化顺序:test.go的全局变量->test.go的init()->add全局变量->add.go的init()->main.go全局变量->main.go的init()
函数特点
- 不支持重载,一个包不能有两个名字一样的函数
- 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
- 匿名函数
- 多返回值
样例:
package main import "fmt" type op_func func(int, int) int func add(a, b int) int { return a + b } func sub(a, b int) int { return a - b } func operator(op op_func, a int, b int) int { return op(a, b) } func main() { c := add fmt.Println(c) sum := operator(c, 100, 200) fmt.Println(sum) var d op_func d = sub fmt.Println(d) sub := operator(d, 100, 200) fmt.Println(sub) }
自定义函数
demo
package main import "fmt" type add_func func(int, int) int func add(a, b int) int { return a + b } func operator(op add_func, a int, b int) int { //使⽤用传进来的函数,进⾏行行操作 return op(a, b) } func main() { c := add fmt.Println(c) sum := operator(c, 100, 200) fmt.Println(sum) }
函数参数传递方式
- 值传递
- 引用传递
注意:无论是值传递,还是引用传递,传递给函数的都是变量的副本。不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
map、slice、chan、指针、interface默认以引用的方式传递。
命名返回值的名字
func add(a, b int) (c int) { c = a + b return } func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a + b)/2 return }
_标识符,用来忽略返回值
func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a + b) / 2 return } func main() { sum, _ := calc(100, 200) }
可变参数
- 0个或多个参数
func add(arg…int) int { }
- 1个或多个参数
func add(a int, arg…int) int { }
- 2个或多个参数
func add(a int, b int, arg…int) int { }
注意:其中arg是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数。
样例:
package main import "fmt" func add(a int, arg...int) int{ var sum int = a for i := 0; i < len(arg); i ++ { sum += arg[i] } return sum } func add_string(a string, arg...string) (result string) { result = a for i := 0; i < len(arg); i ++ { result += arg[i] } return } func main() { sum := add(10, 1 , 2, 3) fmt.Println(sum) str := add_string("hello ", "world ", "wang") fmt.Println(str) }
匿名函数
样例:
package main import "fmt" var( result = func(a1, b1 int) int{ return a1 + b1 } ) func test(a, b int) int { result := func(a1, b1 int) int{ return a1 + b1 }(a, b) return result } func test1(a, b int) int { result := func(a1, b1 int) int{ return a1 + b1 } return result(a, b) } func main() { sum := test(10 , 20) fmt.Println(sum) sum1 := test1(1, 2) fmt.Println(sum1) fmt.Println(result(3,4)) }
defer用途
- 当函数返回时,执行defer语句。因此,可以用来做资源清理
- 多个defer语句,按先进后出的方式执行
- defer语句中的变量,在defer声明时就决定了
样例:
package main import "fmt" func main() { var i int = 0 defer fmt.Println(i) defer fmt.Println("second") i = 10 fmt.Println(i) }
说明:上面代码执行,先将defer压入栈中,当main函数执行完成后,再执行defer内容。多个defer语句,按先进后出的方式执行。同时defer语句的变量i声明时为0,所以结果也为0
使用场景举例:
1、关闭文件句柄
func read() { //文件操作 file := open(filename) defer file.Close() }
2、锁资源释放
func read() { mc.Lock() defer mc.Unlock() // 其他操作 }
3、数据库连接释放
func read() { conn := openDatabase() defer conn.Close() //其他操作 }
内置函数
- close:主要用来关闭channel
- len:用来求长度,比如string、array、slice、map、channel
- new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针
- make:用来分配内存,主要用来分配引用类型,比如chan、map、slice
- append:用来追加元素到数组、slice中
- panic和recover:用来做错误处理
new和make的区别
package main import "fmt" func test() { s1 := new([]int) fmt.Println(s1) s2 := make([]int, 10) fmt.Println(s2) *s1 = make([]int, 5) (*s1)[0] = 100 s2[0] = 100 fmt.Println(s1) return } func main() { test() }
递归函数
函数调用自己,就叫做递归。
递归的设计原则
- 一个大的问题能够分解成相似的小问题
- 定义好出口条件
样例:
package main import ( "fmt" "time" ) func recusive(n int) { fmt.Println("hello", n) time.Sleep(time.Second) if n > 10 { return } recusive(n + 1) } func factor(n int) int { if n == 1 { return 1 } return factor(n-1) * n } func fab(n int) int { if n <= 1 { return 1 } return fab(n-1) + fab(n-2) } func main() { //fmt.Println(factor(5)) recusive(0) /*for i := 0; i < 10; i++ { fmt.Println(fab(i)) }*/ }
闭包
一个函数和与其相关的引⽤用环境组合⽽而成的实体。
demo1:
func Adder() func(int) int { var x int f := func(i int) int { x = x + i return x } return f } func testClosure() { f1 := Adder() fmt.Println(f1(10)) fmt.Println(f1(20)) fmt.Println(f1(30)) f2 := Adder() fmt.Println(f2(10)) fmt.Println(f2(20)) fmt.Println(f2(30)) }
demo2:
package main import ( "fmt" "strings" ) func makeSuffixFunc(suffix string) func(string) string { return func(name string) string { if !strings.HasSuffix(name, suffix) { return name + suffix } return name } } func main() { bmp := makeSuffixFunc(".bmp") jpg := makeSuffixFunc(".jpg") fmt.Println(bmp("test")) fmt.Println(jpg("test")) }