函数定义

type mytype int    // 新的类型
func (p mytype) funcname(q int) (r,s int) {return 0,0}

作用域

在 Go 中,定义在函数外的变量是全局的,那些定义在函数内部的变量,对于函数来说 是局部的。如果命名覆盖——一个局部变量与一个全局变量有相同的名字——在函数 执行的时候,局部变量将覆盖全局变量。

多值返回

func (file *File) Write(b []byte) (n int, err error)
Go得函数可以返回多个值

命名返回值

Go 函数的返回值或者结果参数可以指定一个名字,并且像原始的变量那样使用,就像 输入参数那样。如果对其命名,在函数开始时,它们会用其类型的零值初始化。如果 函数在不加参数的情况下执行了 return 语句,结果参数会返回。
例:

func ReadFull(r Reader, buf []byte) (n int, err error) {
  for len(buf) > 0 && err == nil {
    var nr int
    nr, err = r.Read(buf) n += nr
    buf = buf[nr:len(buf)]
  }
  return
 }

延迟代码defer

在 defer 后指定的 函数会在函数退出前调用。

func ReadWrite() bool {
  file.Open("file")
  defer file.Close()      // file.Close()被添加到了defer列表
  if failureX {
    return false
  }
  if failureY {
    return false
   } 
   return true
}

可以将多个函数放入 “延迟列表”中,例如:

for i:=0; i<5; i++ {
defer fmt.Printf("%d ", i)
}
// 延迟的函数是按照后进先出(LIFO)的顺序执行,所以上面的代码打印:4 3 2 1 0。

利用 defer 甚至可以修改返回值,假设正在使用命名结果参数和函数符号。

defer func() {
/* ... */
}()  // ()在这里是必须的

或者这个例子,更加容易了解为什么,以及在哪里需要括号:

defer func(x int) { /* ... */
}(5) // 为输入参数 x 赋值 5

在这个(匿名)函数中,可以访问任何命名返回参数:

func f() (ret int) { //ret初始化为零 
  defer func() {
    ret++  //ret增加为1
  }() 
  return 0    // 返回的是1而不是0
}

变参

接受不定数量的参数的函数叫做变参函数。定义函数使其接受变参:
func myfunc(arg ...int) { }
arg …int 告诉 Go 这个函数接受不定数量的参数。注意,这些参数的类型全部是 int。
在函数体中,变量 arg 是一个 int 类型的 slice:

for _, n := range arg {
  fmt.Printf("And the number is: %d\n", n)
}

如果不指定变参的类型,默认是空的接口 interface{}(参阅第 5 章)。假设有另一
个变参函数叫做 myfunc2,下面的例子演示了如何向其传递变参:

func myfunc(arg ...int) { myfunc2(arg...) ← 按原样传递
  myfunc2(arg[:2]...) ← 传递部分
}

函数作为值

Go 中函数也是值,函数可以赋值给变量:

func main() {
  a := func() {      // 定义一个匿名函数,并赋值给a
    println("Hello")
  }
  a()  // 调用函数
}

回调

由于函数也是值,所以可以很容易的传递到其他函数里,然后可以作为回调。

func printit(x int) { // 函数无返回值 
  fmt.Printf("%v\n", x) // 仅仅打印
}
func callback(y int, f func(int)) { // f 将会保存函数 
  f(y) // 调用回调函数 f 输入变量 y
}

恐慌(Panic)和恢复(Recover)

Panic:是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。当函数F调用panic,函数F的执行被中断,并且F中的延迟函数会正常执行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一过程继续向上,直到程序崩溃时所有goroutine返回。
恐慌可以直接调用panic产生。也可以由运行时错误产生,例如访问越界的数组。
Recover:是一个内建函数,可以让进入令人恐慌的流程中的goroutine恢复过来。recover仅在延迟函数中有效。
在正常的执行过程中,调用recover会返回nil并且没有其他任何效果。如果当期的goroutine陷入恐慌,调用recover可以捕获到panic的输入值,并且恢复正常的执行。
例:

这个函数检查作为其参数的函数在执行时是否会产生 panic c: .
 func throwsPanic(f func()) (b bool) {//定义一个新函数 throwsPanic 接受一个函数作为参数(参看 “函数作为值”)。函 数 f 产生 panic,就返回 true,否则返回 false;
  defer func() { //定义了一个利用 recover 的 defer 函数。如果当前的 goroutine 产生了 panic,这个 defer 函数能够发现。当 recover() 返回非 nil 值,设置 b 为 true;
     if x := recover(); x != nil { 
         b = true
      }
   }()
 f() // 调用作为参数接收的函数。
 return // 返回 b 的值。由于 b 是命名返回值,无须指定 b。
}