函数

不⽀支持 嵌套 (nested)、重载 (overload) 和 默认参数 (default parameter)。

函数是第⼀一类对象,可作为参数传递。建议将复杂签名定义为函数类型,以便于阅读。

    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)
    }

变参

变参本质上就是 slice。只能有⼀一个,且必须是最后⼀一个。

func test(s string, n ...int) string {
    var x int
    for _, i := range n {
    x += i
    }
    return fmt.Sprintf(s, x)
    }
    func main() {
    println(test("sum: %d", 1, 2, 3))
}

使⽤用 slice 对象做变参时,必须展开。

func main() {
    s := []int{1, 2, 3}
    println(test("sum: %d", s...))
}

延迟执行defer

命名返回参数允许 defer 延迟调⽤用通过闭包读取和修改。

func add(x, y int) (z int) {
    defer func() {
        z += 100
    }()
    z = x + y
    return
}
func main() {
    println(add(1, 2)) // 输出: 103
}

GO中的defer注意点

特性:


defer表达式中变量的值在defer表达式被定义时就已经明确


func a() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}

上面的这段代码,defer表达式中用到了i这个变量,i在初始化之后的值为0,接着程序执行到defer表达式这一行,表达式所用到的i的值就为0了,接着,表达式被放入list,等待在return的时候被调用。所以,后面尽管有一个i++语句,仍然不能改变表达式 fmt.Println(i)的结果。

所以,程序运行结束的时候,输出的结果是0而不是1。

defer表达式的调用顺序是按照先进后出的方式


func b() {
    defer fmt.Print(1)
    defer fmt.Print(2)
    defer fmt.Print(3)
    defer fmt.Print(4)
}

前面已经提到过,defer表达式会被放入一个类似于栈(stack)的结构,所以调用的顺序是后进先出的。所以,上面这段代码输出的结果是4321而不是1234。在实际的编码中应该主意,程序后面的defer表达式会被优先执行。

defer表达式中可以修改函数中的命名返回值.

func c() (i int) {
    defer func() { i++ }()
    return 1
}

上面的示例程序,返回值变量名为i,在defer表达式中可以修改这个变量的值。所以,虽然在return的时候给返回值赋值为1,后来defer修改了这个值,让i自增了1,所以,函数的返回值是2而不是1。

这三个特性需要好好掌握,不然会有很多坑。

匿名函数

匿名函数可赋值给变量,做为结构字段,或者在 channel ⾥里传送。 闭包复制的是原对象指针,这就很容易解释延迟引⽤用现象。

func test() func() {
x := 100
fmt.Printf("x (%p) = %d\n", &x, x)
return func() {
fmt.Printf("x (%p) = %d\n", &x, x)
}
}
func main() {
f := test()
f()
}

results matching ""

    No results matching ""