Go 语言 15 个内置函数详解

2023-09-08 16:18:47 浏览数 (1)

01

介绍

Go 语言为了方便我们开发,提供了 15 个内置函数,比如 lencapmakenew 等。

本文我们结合 Go 内置函数官方文档[1],介绍一下 Go 语言中的内置函数。

02

内置函数

内置函数append

内置函数 append 可以将元素追加到切片的末尾。

代码语言:javascript复制
func append(slice []Type, elems ...Type) []Type

当我们使用 append 向切片中追加元素时,切片的底层数组必须具有足够的容量,否则,将会分配一个新的底层数组。

代码语言:javascript复制
func main() {
 s := []int{1, 2, 3}
 fmt.Printf("%p %dn", s, s)
 s = append(s, 4)
 fmt.Printf("%p %dn", s, s)
}

输出结果:

代码语言:javascript复制
0xc0000b2018 [1 2 3]
0xc0000ae030 [1 2 3 4]

所以,我们需要注意的是,append 之后的切片赋值给同一个变量

除了使用 append 向切片中追加元素之外,我们还可以向切片中追加另一个切片,例如:

代码语言:javascript复制
s1 := []int{5, 6, 7}
s = append(s, s1...)

此外,还可以使用 append 将字符串追加到字节切片中,例如:

代码语言:javascript复制
str := "hello "
bs := append([]byte(str), "world"...)

内置函数copy

内置函数 copy 可以将源切片中的元素拷贝到目标切片。

代码语言:javascript复制
func main() {
 src := []string{"go", "vue"}
 dst := make([]string, 2)
 n := copy(dst, src)
 fmt.Printf("%s %dn", dst, n)
}

输出结果:

代码语言:javascript复制
[go vue] 2

copy 的返回值是拷贝元素的个数,返回值是 len(src)len(dst) 的最小值。

需要注意的是,源切片和目标切片中的元素可能会重叠。

此外,还可以使用 copy 将一个字符串中的字节拷贝到一个字节切片中,例如:

代码语言:javascript复制
func main() {
 str := "hello"
 bs := make([]byte, 5)
 n := copy(bs, str)
 fmt.Printf("%s %dn", bs, n)
}

内置函数delete

内置函数 delete 通过指定键 m[key] 删除 map 中的元素。

如果 mapnil 或没有元素,delete 不做任何操作。

代码语言:javascript复制
func main() {
 var m map[int]string
 fmt.Println(m)
 delete(m, 0)
 fmt.Println(m)
 m1 := make(map[int]string)
 fmt.Println(m1)
 delete(m1, 0)
 fmt.Println(m1)
 m2 := make(map[int]string, 2)
 m2[0] = "hello"
 m2[1] = "world"
 fmt.Println(m2)
 delete(m2, 0)
 fmt.Println(m2)
}

输出结果:

代码语言:javascript复制
map[]
map[]
map[]
map[]
map[0:hello 1:world]
map[1:world]

内置函数 len

内置函数 len 返回值的长度,值的类型不同,值的长度含义也不同。

  • array 数组中元素的个数。
  • *array 数组指针中元素的个数,即使数组指针的值是 nil
  • slicemap 切片或映射中元素的个数,如果切片或映射的值是 nillen(v) 值的长度是 0。
  • string 字符串中字节的个数。
  • channel 通道缓冲区中未读元素的个数,如果缓冲通道的值是 nillen(v) 值的长度是 0。
代码语言:javascript复制
func main() {
 arr := [3]int{1, 2, 3}
 fmt.Println(arr)
 fmt.Println(len(arr))
 var arr1 *[3]int
 fmt.Println(arr1)
 fmt.Println(len(arr1))
 var s []int
 fmt.Println(len(s))
 s = []int{1, 2, 3}
 fmt.Println(len(s))
 var m map[int]string
 fmt.Println(len(m))
 m = make(map[int]string)
 m[0] = "hello"
 fmt.Println(len(m))
 str := "frank"
 fmt.Println(len(str))
 var c chan int
 fmt.Println(c)
 fmt.Println(len(c))
 c = make(chan int)
 fmt.Println(len(c))
}

输出结果:

代码语言:javascript复制
[1 2 3]
3
<nil>
3
0
3
0
1
5
<nil>
0
0

需要注意的是,slicemapchannel 必须先使用内置函数 make 初始化后,该类型的值才可以使用。

内置函数 cap

内置函数 cap 返回值的容量,值的类型不同,值的容量含义也不同。

  • array 数组中元素的个数,数组的 cap(v)len(v) 相等。
  • *array 数组指针中元素的个数,数组指针的 cap(v)len(v) 相等。
  • slice 切片可以容纳元素的最大长度,如果切片的值是 nil,该切片 cap(v) 值的容量是 0。
  • channel 通道缓冲区的容量,如果通道的值是 nil,该通道 cap(v) 值的容量是 0。
代码语言:javascript复制
func main() {
 var arr [3]int
 fmt.Println(arr)
 fmt.Println(cap(arr))
 var arr1 *[3]int
 fmt.Println(arr1)
 fmt.Println(cap(arr1))
 var s []string
 fmt.Println(s)
 fmt.Println(cap(s))
 s = make([]string, 1)
 s[0] = "go"
 fmt.Println(s)
 fmt.Println(cap(s))
 var c chan int
 fmt.Println(c)
 fmt.Println(cap(c))
}

输出结果:

代码语言:javascript复制
[0 0 0]
3
<nil>
3
[]
0
[go]
1
<nil>
0

内置函数 make

内置函数 make 仅限为 slicemapchannel 分配内存并初始化。

代码语言:javascript复制
func make(t Type, size ...IntegerType) Type

make 第一个参数是类型,而不是值;第二个参数是可选(变长)参数,整型类型的值,返回值是该类型的值本身。

需要注意的是,第一个参数不同(不同类型),第二个参数的含义不同。

  • slice 第一个参数是切片类型,第二个参数的含义是指定切片的长度。如果没有传递第三个参数(整型类型的值),切片的容量等同于切片的长度,否则,切片的容量等同于第三个参数的值,需要注意的是,切片的容量必须不小于切片的长度。
  • map 分配一个有足够空间可以容纳指定数量元素的空映射,第二个参数可以省略,如果省略第二个参数,将分配一个起始值 0。
  • channel 指定缓冲区大小,初始化通道,如果第二个参数省略,或指定值为 0,该通道将被初始化为一个无缓冲通道。

内置函数 new

内置函数 new 也可以分配内存,与 make 的区别是,它仅分配内存,而未初始化。

make 相同,第一个参数是类型,而不是值;

make 不同,返回值是新分配的类型零值的指针。

内置函数 complex

内置函数 complex 将两个浮点型的值构造为一个复合类型的值,需要注意的是,实部和虚部必须是相同类型,即都是 float32float64

返回值是对应的复合类型,即 complex64 对应 float32complex128 对应 float64

内置函数 real

内置函数 real 用于返回复合类型的值的实部,返回值是对应的浮点数类型。

内置函数 imag

内置函数 imag 用于返回复合类型的值的虚部,返回值是对应的浮点数类型。

注意:complexrealimag 三个内置函数,一般不常用,读者朋友们只需简单了解即可。

内置函数 close

内置函数 close 关闭通道,被关闭的通道必须是一个双向通道或仅支持发送的单向通道。

并且 close 应该由发送者执行,结果是在最后一个发送的值被接收后,关闭该通道。

通道被关闭后,任何该通道的接收者将返回成功而不会阻塞,接收者得到的返回值是该通道的类型零值和一个布尔类型的零值 false

需要注意的是,不仅是关闭通道会返回 false,空通道也会返回 false

内置函数 panic

内置函数 panic 停止当前 goroutine 正常执行,当一个函数 F 调用 panic 时,该函数 F 立即停止正常执行。

该函数 F 通过 defer 延迟调用的任意函数,仍然会执行,并将执行结果返回给 F 调用者。

对于 F 的调用者 F2,调用 F 也会像调用 panic,停止 F2 的执行,并运行 F2 通过 defer 延迟调用的任意函数。以此类推,一直持续到当前 goroutine 中的所有函数都以相反的顺序停止运行。

此时,程序以非 0 退出代码终止运行。

以上终止程序运行的序列称为“恐慌”,可以通过接下来我们要介绍的内置函数 recover 进行控制。

内置函数 recover

内置函数 recover 允许程序管理“恐慌”的 goroutine 的行为。

可以在 defer 中调用 recover 恢复正常执行来停止“恐慌”,并且检索导致“恐慌”的错误。

但是,如果在 defer 之外调用 recover,它不会恢复正常执行来停止“恐慌”。此种情况,recover 的返回值是 nil。此外,当前执行 recovergoroutine 未“恐慌”,或调用 panic(nil) 时,recover 的返回值也是 nil

因此,我们可以通过 recover 的返回值,判断当前 goroutine 是否“恐慌”。

注意:此处讲的在 defer 中调用 recover,是指在 defer 本身中,而不是任何被 defer 调用的函数中。

内置函数 print

内置函数 print 可以通过指定格式来格式化其参数,并将结果输出。

内置函数 println

内置函数 println 可以通过指定格式来格式化其参数,并将结果输出。与 print 的区别是,参数之间会添加空格,末尾会添加换行符。

注意:printprintln 与标准库 fmt 中的 fmt.Print()fmt.Println() 的区别是,前者是标准错误输出,后者是标准输出。在 Go 语言开发中,官方推荐使用标准库 fmt 包,感兴趣的读者朋友们可以查阅相关资料进一步了解。

03

总结

本文我们介绍 Go 语言的内置函数,读者朋友们需要重点掌握的内置函数是 lencapmakenewappendcopydeleteclosepanicrecover

Go 语言作为静态编程语言,分为编译期和运行时,Go 语言的内置函数的底层原理,感兴趣的读者朋友们可以阅读 Go 语言内置函数的源码[2]

推荐阅读:

  1. Go 语言实现创建型设计模式 - 单例模式
  2. Go 语言各个版本支持 Go Modules 的演进史
  3. Go 1.18 新增三大功能之一“模糊测试”使用方式
  4. Go 语言学习之 goroutine 和 channel
  5. Go 语言学习之测试

参考资料

[1]

Go 内置函数官方文档: https://pkg.go.dev/builtin@go1.20.3

[2]

Go 语言内置函数的源码: https://cs.opensource.google/go/go/ /refs/tags/go1.20.3:src/cmd/compile/internal/typecheck/universe.go

0 人点赞