16.3 内置函数

Go 语言拥有一些内置函数,内置函数是预先声明的,它们像任何其他函数一样被调用,内置函数没有标准的类型,因此它们只能出现在调用表达式中,它们不能用作函数值。

它们有时可以针对不同的类型进行操作:

内置函数 说明
close 用于通道,对于通道c,内置函数close(c)将不再在通道c上发送值。 如果c是仅接收通道,则会出错。 发送或关闭已关闭的通道会导致运行时错误。 关闭nil通道也会导致运行时错误。
new、make new 和 make 均是用于分配内存:new用于值类型的内存分配,并且置为零值。make只用于slice、map以及channel这三种引用数据类型的内存分配和初始化。new(T) 分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针。make(T) 它返回类型T的值(不是* T)。

make()内置函数声明不同类型时的参数以及具体作用请见下面说明:

调用           T的类型     结果
make(T, n)       slice        T为切片类型,长度和容量都为n
make(T, n, m)     slice        T为切片类型,长度为n,容量为m (n<=m ,否则错误)
make(T)          map        T为字典类型
make(T, n)        map        T为字典类型,初始化n个元素的空间
make(T)          channel      T为通道类型,无缓冲区
make(T, n)        channel      T为通道类型,缓冲区长度为n

make() 内置函数的实际使用举例见下面代码以及注释:

s := make([]int, 10, 100)       // slice with len(s) == 10, cap(s) == 100
s := make([]int, 1e3)           // slice with len(s) == cap(s) == 1000
s := make([]int, 1<<63)         // illegal: len(s) is not representable by a value of type int
s := make([]int, 10, 0)         // illegal: len(s) > cap(s)
c := make(chan int, 10)         // channel with a buffer size of 10
m := make(map[string]int, 100)  // map with initial space for approximately 100 elements

new(T) 内置函数在运行时为该类型的变量分配内存,并返回指向它的类型* T的值。 并对变量初始化。例如:

type S struct { a int; b float64 }
new(S)

new(S) 为S类型的变量分配内存,并初始化(a = 0,b = 0.0),返回包含该位置地址的类型* S的值。

内置函数 参数类型 结果
len(s) string type ,[n]T, *[n]T ,[]T ,map[K]T ,chan T string的长度(按照字节计算),数组长度 ,切片长度 ,字典长度 ,通道缓冲区中排队的元素数
cap(s) [n]T, *[n]T ,[]T ,chan T 数组长度 ,切片容量 ,通道缓冲区容量

对于len(s)和cap(s),如果s为nil值,则两个函数的取值都是0,我们还需要记住一个规则:

0 <= len(s) <= cap(s)

Go语言中,常量在某些计算条件下也可以通过表达式计算得到。比如:如果s是字符串常量,则表达式len(s)是常量。 如果s的类型是数组或指向数组的指针而表达式不包含通道接收或(非常量)函数调用,则表达式len(s)和cap(s)是常量;否则len和cap的调用不是常量。

const (
	c1 = imag(2i)                  // imag(2i) = 2.0 是常量
	c2 = len([10]float64{2})         // [10]float64{2} 无函数调用
	c3 = len([10]float64{c1})        // [10]float64{c1} 无函数调用
	c4 = len([10]float64{imag(2i)})   // imag(2i)常量无函数调用
	c5 = len([10]float64{imag(z)})    // 无效: imag(z) 非常量函数调用
)
var z complex128
内置函数 说明
append 用于附加连接切片
copy 用于复制切片
delete 从字典删除元素
append(s S, x ...T) S  // T 是类型S的元素

append内置函数是变参函数,常常用来附加切片元素,将零或多个值x附加到S类型的切片s,它的可变参数必须是切片类型,并返回结果切片,也就是是S类型。值x传递给类型为...的参数T,其中T 是S的元素类型,并且适用相应的参数传递规则:

s0 := []int{0, 0}
s1 := append(s0, 2)            // append 附加连接单个元素   s1 == []int{0, 0, 2}
s2 := append(s1, 3, 5, 7)        // append 附加连接多个元素  s2 == []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...)         // append 附加连接切片s0  s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
s4 := append(s3[3:6], s3[2:]...)  // append 附加切片指定值 s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
var t []interface{}
t = append(t, 42, 3.1415, "foo")  //  t == []interface{}{42, 3.1415, "foo"}
var b []byte
b = append(b, "bar"...)         // append 附加连接字符串内容  b == []byte{'b', 'a', 'r' }
copy(dst, src []T) int
copy(dst []byte, src string) int

copy内置函数常常将切片元素从源src复制到目标dst,并返回复制的元素数。 两个参数必须具有相同的元素类型T,并且必须可以分配给类型为[] T的切片。 复制的元素数量是len(src)和len(dst)的最小值。

作为特殊情况,copy函数还接受可分配给[] byte类型的目标参数,其中source参数为字符串类型。 此种情况将字符串中的字节复制到字节切片中。

var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
var s = make([]int, 6)
var b = make([]byte, 5)
n1 := copy(s, a[0:])            // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
delete(m, k)  //从字典m中删除元素 m[k] 

内置函数delete从字典m中删除带有键k的元素。

内置函数 说明
complex 从浮点实部和虚部构造复数值
real 提取复数值的实部
imag 提取复数值的虚部
complex(realPart, imaginaryPart floatT) complexT
real(complexT) floatT
imag(complexT) floatT

内置函数complex用浮点实部和虚部构造复数值,而real和imag则提取复数值的实部和虚部。

对于complex,两个参数必须是相同的浮点类型,返回类型是具有相应浮点组成的复数类型。float32用于complex64参数,float64用于complex128参数。如果其中一个参数求值为无类型常量,则首先将其转换为另一个参数的类型。如果两个参数都计算为无类型常量,则它们必须是非复数或其虚部必须为零,并且函数的返回值是无类型复数常量。

对于real和imag,参数必须是复数类型,返回类型是相应的浮点类型:float32一般为complex64返回类型,float64一般为complex128返回类型。如果参数求值为无类型常量,则它必须是数字,并且函数的返回值是无类型浮点常量。

real和imag函数一起形成复数的逆,因此对于复数类型Z的值z,z == Z(complex(real(z),imag(z)))。

如果这些函数的操作数都是常量,则返回值是常量。

var a = complex(2, -2)             // complex128
const b = complex(1.0, -1.4)        // 无类型complex 常量 1 - 1.4i
x := float32(math.Cos(math.Pi/2))   // float32
var c64 = complex(5, -x)          // complex64
var s uint = complex(1, 0)         // 无类型 complex 常量 1 + 0i 可以转为uint
var rl = real(c64)                // float32
var im = imag(a)                // float64
const c = imag(b)               // 无类型常量 -1.4
内置函数 说明
panic 用来表示非常严重的不可恢复的异常错误
recover 用于从 panic 或 错误场景中恢复
func panic(interface{})
func recover() interface{}

panic和recover两个内置函数,协助报告和处理运行时异常和程序定义的错误。

在执行函数F时,显式调用panic或者运行时发生panic都会终止F的执行。然后,由F延迟(defer)的任何函数都照常执行。 依此类推,直到执行goroutine中的顶级函数延迟。 此时,程序终止并报告错误条件,包括panic参数的值。

panic(42)
panic("unreachable")
panic(Error("cannot parse"))

recover函数允许程序管理发生panic的goroutine的行为。

另外,Go语言中提供了几个在引导期间有用的内置函数。 这些函数不保证会保留在Go语言中,一般不建议使用。

print      打印所有参数
println    打印所有参数并换行
下一节:函数直接或间接调用函数本身,则该函数称为递归函数。