函数


注意 Go中没有函数重载

函数定义

func name(arg1 type,arg2 type...) return_type{
    
}

命名返回值

package main

import "fmt"

func add_all(arr []int) (sum int) {
 for _, v := range arr {
  sum += v
 }
 return
}

func main() {
 a := [...]int{1, 2, 3, 4, 5}
 fmt.Println(add_all(a[:]))
}

多返回值

package main

import "fmt"

func add_all(arr []int) (indexsum, sum int) {
 for i, v := range arr {
  indexsum += i
  sum += v
 }
 return
}
func main() {
 a := [...]int{1, 2, 3, 4, 5}
 fmt.Println(add_all(a[:]))// 10 15
}

变长参数

package main

import "fmt"

func add_all(cnt int, arr ...int) (sum int) { //变长参数只能放在最后面
 for i := 0; i < cnt; i++ {
  sum += arr[i]
 }
 return
}
func main() {
 fmt.Println(add_all(3, 1, 2, 3))
}

闭包函数

匿名函数

go中函数也是一个类型,可以达到在函数中定义函数的效果。

package main

import "fmt"

func main() {
 var x int = 1
 var fun = func(a int) (ans int) {
  x = 2
  ans = a * a
  return
 }
 fmt.Println(fun(2), x)
}
package main

import "fmt"

func f(i int) func() int {
 return func() int {
  i++
  return i
 }
}

func main() {
 var c = func(a, b int) (sum int) {
  sum = a + b
  return
 }(1, 2)
 fmt.Println(c)//3
}

闭包

package main

import "fmt"

func f(i int) func() int {
 return func() int {
  i++
  return i
 }
}

func main() {
 var c = f(0)
 fmt.Println(c(), c())//1,2
}

上面的例子中,i这个变量escape了,到了heap 中,所以每次调用的都是同一个i,

其实返回的不只有这个函数,还返回了函数外层的变量引用,实际上是返回了一个结构体,里面有函数和变量的地址。当调用函数的时候就是在调用这个匿名函数

识别出变量需要在堆上分配,是由编译器的一种叫escape analyze的技术实现的。如果输入命令:

go build --gcflags=-m main.go
package main

import "fmt"

func f(i int) func() int {
 return func() int {
  i++
  return i
 }
}

func main() {
 var c = f(0)
 var d = f(0)
 fmt.Println(c(), d())// 1 1
}

cd处在两个不同的环境,所以不会影响别人的i。返回闭包时并不是单纯返回一个函数,而是返回了一个结构体,记录下函数返回地址和引用的环境中的变量地址。

看这里

异常处理

defer

defer关键字会将函数压入栈中,等到外层函数退出即将时再从栈中取出运行

package main

import "fmt"

func main() {
 defer fmt.Print("B")
 fmt.Println("A")
}// A B

文章作者: ffacs
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 ffacs !
  目录