Skip to content

Go 语言笔记:函数

函数定义

函数声明,主要包含 func 关键字, 返回值类型 return_type(如 c int 或不指定变量名 c),和入参 parameter_list (如 a int, b int)

go
// 函数定义结构
func name ([parameter_list]) [return_type] {
    函数体
}

// 函数定义示例
func add(a int, b int) (c int) {
    return a + b;
}

Go 函数不支持重载

同一个包不能相同名称的函数,如下编译器会报错:foo redeclared int this package

go
func foo() int {
     return 2;
}


func foo(a int) (b int, c int) {
     return 2, 3;
}

函数返回值

Go 函数支持返回值不写变量名,如下面的减法操作,c 可忽略掉,且只有一个返回值时,不需要 () 包装

go
// 当返回值存在命名,`return` 可以不指定返回值变量
func add(a int, b int) (c int) {
    c = a + b
    return
}

// 当返回值不存在命名,`return` 后面必须显式返回结果
func sub(a int, b int) int {
    return a - b
}

函数返回值的接收

函数的返回值可以赋给变量, 同时某些返回值也可以标识符 _ 忽略接收

go
func add(a int, b int) (c int) {
    c = a + b
    return
}

func calculate(a int, b int) (sum int, sub int) {
    sum = a + b
    sub = a - b
    return 
}

fun main() {
    sum := add(100, 200)
    println(sum) // 300
    sum, sub := calculate(100, 200)
    println(sum, sub) // 300, -100
    _, sub := calculate(200, 200)
    println(sub) // 0
    // 注意这里已经不存在新的变量,属于重新赋值,使用 `=` 即可
    sum, _ = calculate(200, 200) 
    println(sub) // 0
}

函数类型

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

go
package main

import "fmt"

// 声明函数类型
type calc func(a, b int) int

func add(a, b int) int {
    return a + b
}

func operate(op calc, a int, b int) int {
    return op(a, b)
}

func main() {
    // 将函数类型赋值给变量 `function`
    function := add
    // 打印函数地址
    println(function)
    // 将函数类型作为入参
    sum := operate(function, 5, 10)
    println(sum)
}

可变参数

可变参数,实际上是一个slice切片类型,可以通过下标索引的方式访问,可以使用内置函数 len 来统计其长度,且可变参数只能放在函数入参的最后一个位置

func add(a int, args... int) int {
    函数体 
}

func concat(s string, arg ...string) string {
    str := s
    for i := 0; i < len(arg); i++ {
        str += arg[i]
    }
    return str
}

main 函数 和 init 函数

  • main 函数只能用在 package main 包中,且 package main 包中必须包含 main 函数
  • main 函数不能有入参,命令行传入的参数可以使用 os.Args 获取,命令行开关打开需要导入 flag
  • init 函数可以出现在任何的 package 中,是可选的,也可以不出现
  • maininit 函数不需要手动调用,Go 程序会自动执行这两个函数

函数作用域

  • 在函数体内部声明的变量是局部变量,生命周期仅限于函数内部
  • 在函数体外部声明的变量是全局变量,生命周期作用于整个包,如果函数名是大写的,做作用于整个程序
go
package main

import "fmt"

var age int
 
func main() {
    age = 18
    println(age)
    foo()
}

func foo() {
    age := 20
    println(age)
    foo2()
}

func foo2() {
    println(age)
}

输出:
18
20
18

匿名函数

匿名函数,即没有函数名,由函数声明和函数体组成

go
func main() {
    // 匿名函数赋值给变量 foo
    foo := func(a, b int) int {
        return a + b
    }
    
    println(foo(2, 3))
}

闭包

闭包是函数和与其相关的引用环境组合而成的结构实体,函数可以存储到变量中作为参数传递给其他函数

go
package main

import "fmt"

func calculate() func(int) int {
    var x int
    return func(d int) int {
        x += d
	return x
    }
}

func main() {
    f := calculate()
    fmt.Println(f(1))           // 1
    fmt.Println(f(10))          // 11
    fmt.Println(f(100))         // 111
    
    println(calculate()(1))     // 1
    println(calculate()(10))    // 10
    println(calculate()(100))   // 100
}

上述的 f := calculate() 操作,会将函数变量赋值给变量 ff 就此成为了一个闭包,f 保存着对 x 的引用,由于 f 有着指向 x 的指针,因此后面重复调用 f 时,f 指向 x 的值还是上一次的结果,导致了 x 逃逸了,生命周期没有结束。而多次调用 calculate()(x) 方法是分别返回了不同的闭包,因此函数体内的 x 不会对下一个闭包产生影响,因为他们是不同的闭包

Released under the MIT License.