徐旭 的个人博客

【极简Golang入门】函数

函数

Go 里面有三种类型的函数:

  • 普通的命名函数
  • 匿名函数或者lambda函数
  • 方法

函数参数和返回值

除 main() 、init() 函数外,Go 中其它所有类型的函数都可以有参数与返回值。

函数参数、返回值及它们的类型被统称为函数签名。函数可以返回零个或多个值,相较于 C/C++ 等语言多值返回是 Go 的一大特性。

func Test1(a, b int) int {
    return a + b
}
func Test2(a, b int) (int, int) {
    return b, a
}

命名返回值

命名返回值作为结果形参被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的return语句。

func Test3() (ret1 int, ret2 int){
    ret1 = 1
    ret2 = 2

    return
}

按值传递

Go 中默认都是使用按值传递,也就是说函数传参时都会拷贝一个副本出来到函数内部使用。

如果不希望拷贝带来太大的性能开销,或者希望可以改变参数的内容,可以传递指针。

a := 1
f(&a)

指针也是一个变量,函数传参时同样时按值传递,只不过拷贝的是指针,也就是变量的地址。指针通常是一个32位或者64位的值,所以性能开销比传递一些结构体要小的多。

在 Go 中也有一些按引用传递的类型:切片(sleice)、字典(mao)、接口(interface)、通道(chan)。其实,这些类型的底层同样是使用指针来实现的。

例如,切片的底层是一个指针指向一片内存的首地址,len 记录已用内存的长度,cap 记录切片的容量。在传递切片时,仅仅会将这三个值拷贝一份,而不会去拷贝切片里的全部数据。所以,我们在使用 Go 自带的这些引用类型时可以直接传参,无需担心性能开销而传递指针。

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

变长参数

Go 中支持变长参数,在函数的最后一个参数采用 ...type 的形式,可以传递 0 个或者多个参数。

func f(a int , args ...int) {
}
...

f(1, 23, 45, 67, 89)

如果参数是数组或者切片,可以通过 val... 来自动展开。

sl := []int{1, 2, 3}

f(1, sl...)

defer

关键字 defer 允许我们推迟到函数返回之前(或任意位置执行 return 语句之后)一刻才执行某个语句或函数。

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

当有多个 defer 行为被注册时,它们会以 defer 的出现顺序逆序执行(类似栈,即后进先出)。
使用 defer 会有一定的性能开销,但是 defer 在程序 panic 的时候,还保证会执行。所以通过我们会使用 defer 进行一些函数执行收尾工作。例如,关闭文件描述符,解锁等。

闭包

Go 支持匿名函数,函数在 Go 中是一等公民,可以将函数赋值给变量,在需要时再执行。

f = func() {
    fmt.Println("func")
}

f()

// 直接执行
func() {
 fmt.Println("func")
}()

匿名函数同样被称之为闭包,闭包可使得某个函数捕捉到一些外部状态。例如:引用一些外部变量,这些变量可以在闭包中被操作,生命周期延长至和闭包一样。

func fun() func() {
	i := 1
	return func() {
		i++
		fmt.Println(i)
	}
}

func fun1(f func()) {
	f()
}

func main() {
	fmt.Println("Hello World")
	f := fun()
	f()         // 2
	f()         // 3

	fun1(f)     // 4
}

init 函数

init 函数是 Go 中一个特殊函数,每个包都可以有 init 函数,它先于 main 函数执行,用于做一些初始化操作。

init 函数的主要特点:

  • init 函数在全局变量初始化之后,main 函数执行前自动执行,不能被手动调用
  • init 函数没有参数和返回值
  • 每个包可以包含多个 init 函数,同一个包的 init 函数间的执行顺序不确定
  • 不同包内的 init 函数按照导入包的顺序执行
package main                                                                                                                     
import (
   "fmt"              
)

var T int = a()

func a() int {
   fmt.Println("var T int64 = a()")
   return 1
}

func init() {
   fmt.Println("init()")
}

func main() {                  
   fmt.Println("main()")     
}

输出:

var T int64 = a()
init()
main()


标题:【极简Golang入门】函数
作者:Allenxuxu
地址:https://note.mogutou.xyz/articles/2019/08/04/1564914678382.html
Github: https://github.com/Allenxuxu

评论