Go语言函数深入解析

目录函数定义参数返回值匿名函数函数可变数量参数传参闭包递归延迟调用defer异常处理单元测试压力测试函数定义golang函数特点:无需声明原型。支持不定变参。支持多返回值。支持命名返回参数。支持匿名函数和闭包。函数也是一种类型,一

目录


函数定义

golang函数特点:

  • 无需声明原型。

  • 支持不定 变参。

  • 支持多返回值。

  • 支持命名返回参数。

  • 支持匿名函数和闭包。

  • 函数也是一种类型,一个函数可以赋值给变量。

  • 不支持 嵌套 (nested) 一个包不能有两个名字一样的函数。

  • 不支持 重载 (overload)

  • 不支持 默认参数 (default parameter)。

    package main
    import "fmt"
    func test(fn func() int) int {
    return fn()
    }
    // 定义函数类型。
    type FormatFunc func(s string, x, y int) string 
    func format(fn FormatFunc, s string, x, y int) string {
    return fn(s, x, y)
    }
    func main() {
    s1 := test(func() int { return 100 }) // 直接将匿名函数当参数。
    
    s2 := format(func(s string, x, y int) string {
        return fmt.Sprintf(s, x, y)
    }, "%d, %d", 10, 20)
    
    println(s1, s2)
    }

参数

函数定义时指出,函数定义时有参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量。

但当调用函数,传递过来的变量就是函数的实参,函数可以通过两种方式来传递参数:

  • 值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
  • 引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

    
    package main
    import (
    "fmt"
    )
    /* 定义相互交换值的函数 */
    func swap(x, y *int) {
    var temp int
    
    temp = *x /* 保存 x 的值 */
    *x = *y   /* 将 y 值赋给 x */
    *y = temp /* 将 temp 值赋给 y*/

} func main() { var a, b int = 1, 2 / 调用 swap() 函数 &a 指向 a 指针,a 变量的地址 &b 指向 b 指针,b 变量的地址 / swap(&a, &b) fmt.Println(a, b) }

### 任意类型的不定参数:
```go
package main
import (
    "fmt"
)
func test(s string, n ...int) string {
  var x int
  for _, i := range n {
      x += i
  }
  return fmt.Sprintf(s, x)
}
func main() {
  s := []int{1, 2, 3}
  res := test("sum: %d", s...)    // slice... 展开slice
  println(res)
}

返回值

没有参数的 return 语句返回各个返回变量的当前值。这种用法被称作“裸”返回。

package main
import (
  "fmt"
)
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 test() (int, int) {
  return 1, 2
}
func sum(n ...int) int {
  var x int
  for _, i := range n {
      x += i
  }
  return x
}
func addp(x, y int) (z int) {
  defer func() {
      println(z) // 输出: 203   defer 延迟调用通过闭包读取和修改
  }()

  z = x + y
  return z + 200 // 执行顺序: (z = z + 200) -> (call defer) -> (return)
}
func main() {
  var a, b int = 1, 2
  c := add(a, b)
  sum, avg := calc(a, b)
  fmt.Println(a, b, c, sum, avg)
  x, _ := test()
  println(x)
  println(add(1, 2))    // 命名返回参数可看做与形参类似的局部变量,最后由 return 隐式返回。
  println(sum(test()))  // 多返回值可直接作为其他函数调用实参。
  println(add(1, 2))   // 显式 return 返回前,会先修改命名返回参数。
}

匿名函数

匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。

package main

func main() {
  // 匿名函数申明
  getSqrt := func(a float64) float64 {
      return math.Sqrt(a)
  }
  fmt.Println(getSqrt(4))

  // --- function variable ---
  fn := func() { println("Hello, World!") }
  fn()

  // --- function collection ---
  fns := [](func(x int) int){
      func(x int) int { return x + 1 },
      func(x int) int { return x + 2 },
  }
  println(fns[0](100))

  // --- function as field ---
  d := struct {
      fn func() string
  }{
      fn: func() string { return "Hello, World!" },
  }
  println(d.fn())

  // --- channel of function ---
  fc := make(chan func() string, 2)
  fc <- func() string { return "Hello, World!" }
  println((<-fc)())
}

闭包递归

Go 闭包

package main

import "fmt"

// 外部引用函数参数局部变量
func add(base int) func(int) int {
    return func(i int) int {
        base += i
        return base
    }
}

// 返回2个函数类型的返回值
func test01(base int) (func(int) int, func(int) int) {
    // 定义2个函数,并返回
    // 相加
    add := func(i int) int {
        base += i
        return base
    }
    // 相减
    sub := func(i int) int {
        base -= i
        return base
    }
    // 返回
    return add, sub
}

func main() {
    tmp1 := add(10)
    fmt.Println(tmp1(1), tmp1(2))
    // 此时tmp1和tmp2不是一个实体了
    tmp2 := add(100)
    fmt.Println(tmp2(1), tmp2(2))

    f1, f2 := test01(10)
    // base一直是没有消
    fmt.Println(f1(1), f2(2))
    // 此时base是9
    fmt.Println(f1(3), f2(4))
}

Go 递归

// 数字阶乘
package main
import "fmt"
func factorial(i int) int {
  if i <= 1 {
      return 1
  }
  return i * factorial(i-1)
}
func main() {
    var i int = 7
    fmt.Printf("Factorial of %d is %d\n", i, factorial(i))
}

// 斐波那契数列(Fibonacci)
package main
import "fmt"
func fibonaci(i int) int {
  if i == 0 {
      return 0
  }
  if i == 1 {
      return 1
  }
  return fibonaci(i-1) + fibonaci(i-2)
}
func main() {
  var i int
  for i = 0; i < 10; i++ {
      fmt.Printf("%d\n", fibonaci(i))
  }
}

延迟调用defer

go语言 def...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论