函数

编程语言通过函数划分不同的代码块,函数调用在底层通过栈实现。这篇笔记我们学习Go语言中函数相关的语法。

main函数

和大多数编程语言一样,main是一个特殊的函数作为代码逻辑的入口,在Go语言中main函数必须位于package main中。

package main

import "fmt"

func main() {
    fmt.Printf("Hello, world!\n")
}

不过和C语言不同的是,Go的main函数不能带有参数,接收命令行参数需要使用os.Args变长数组。

package main

import (
    "fmt"
    "os"
)

func main() {
    for _, arg := range os.Args {
        fmt.Printf("%v\n", arg)
    }
}

自定义函数

Go语言中声明函数的格式如下。

func function_name( [parameter list] ) [return_types] {
   // 函数体
}

参数传递

函数传递参数时,要注意值传递和引用传递,这和C语言类似。Go语言中,引用传递使用指针实现,变长数组、字典等本身就是引用类型,因此可以不用指针。下面代码中,i是值传递,j则是引用传递,其真正的值被foo函数修改了。

package main

import "fmt"

func foo(i int, j *int) {
    i += 1
    *j += 1
}

func main() {
    var i, j int = 0, 0
    foo(i, &j)

    fmt.Printf("%v %v\n", i, j)
}

函数返回值

函数返回值的用法和其他语言都类似,不过这里要注意的是,类似Python语言,Go语言的函数可以有多个返回值,用法例子如下。

func foo() (int, string) {
    return 0, "hello"
}

读取其返回值时,我们可以使用如下写法。

var i int
var s string
i, s = foo()

也可以简写为自动类型推导的声明和赋值。

i, s := foo()

我们不关心的类型可以将其忽略。

i, _ := foo()

函数指针

类似C语言的函数指针,Go语言中函数也可以作为一个变量使用。

假设我们有这样一个函数:

func increment(i int) int {
    return i + 1
}

那么我们其实已经可以用increment进行赋值、参数传递等操作。下面代码我们将increment赋值给了变量fn

var fn func(i int) int = increment

注意这里定义的fn的类型为func(i int) int,对应函数声明的参数列表和返回值。当然这一串写起来可能比较复杂,这里我们可以使用类型推导简写,这里就不多说了。

回调函数

函数指针可以很容易的实现回调函数,下面例子代码中,我们的foo函数需要传入一个函数指针作为参数,foo函数执行最后会将其调用。

package main

import "fmt"

func foo(fn func()) {
    fmt.Printf("Processing data...\n")
    fn()
}

func callback() {
    fmt.Printf("Success!\n")
}

func main() {
    foo(callback)
}

匿名函数

其实上面代码中的callback函数可以使用匿名函数简化,例子代码如下。

package main

import "fmt"

func foo(fn func()) {
    fmt.Printf("Processing data...\n")
    fn()
}

func main() {
    foo(func() {
        fmt.Printf("Success!\n")
    })
}

此外,匿名函数也可以作为返回值,这在下面介绍的闭包中很常用。

闭包

匿名函数可以直接访问上一层函数内部的变量,因此可以实现闭包,下面例子代码中我们使用闭包实现输出一个自增的变量。

package main

import "fmt"

func next() func() int {
    var i int = 0
    return func() int {
        i += 1
        return i
    }
}

func main() {
    fn := next()
    fmt.Printf("%v\n", fn())
    fmt.Printf("%v\n", fn())
    fmt.Printf("%v\n", fn())
}

这里注意我们是先使用变量fn接收了next()函数的返回值,然后每次调用fn()函数,这里不要搞错写成每次执行next()(),这种写法每次next()返回的都是新的函数。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap