内建函数
1、预定义了少数函数,这意味着无需引用任何包就可以使用它们
close 用于 channel 通讯。
delete 用于在 map 中删除实例
len 和 cap 可用于不同的类型, len 用于返回字符串、slice 和数组的长度。
new 用于各种类型的内存分配。
make 用于内建类型(map、slice 和 channel)的内存分配。
copy 用于复制 slice。
append 用于追加 slice。
panic 和 recover 用于异常处理机制。
print 和 println 是底层打印函数,可以在不引入 fmt 包的情况下使用。它们 主要用于调试。
complex、real 和 imag 全部用于处理 复数。
可以利用 array 在列表中进行多个值的排序,或者使用更加灵活的:slice。字典
或哈希类型同样可以使用,在 Go 中叫做 map。
2、array
array 由 [n]<type> 定义, n 标示 array 的长度,而 <type> 标示希望存储的内容的 类型。
对 array 的元素赋值或索引是由方括号完成的:
var arr [10]int
arr[0] = 42
arr[1] = 13
fmt.Printf("The first element is %d\n", arr[0])
像 var arr = [10]int 这样的数组类型有固定的大小。大小是类型的一部分。由于不同的大小是不同的类型,因此不能改变大小。
数组同样是值类型的:将一个数组赋值给另一个数组,会复制所有的元素。
尤其是当向函数内传递一个数组的时候,它会获得一个数组的副本,而不是数组的指针。
可以像这样声明一个数组:var a [3]int,如果不使用零来初始化它,
则用复合声明:a := [3]int{1, 2, 3} 也可以简写为 a := [...]int{1, 2, 3},Go 会自动统计元素的个数。
注意,所有项目必须都指定。因此,如果你使用多维数组,有一些内容你必须录入:
a := [2][2]int{ [2]int{1,2}, [2]int{3,4} } 类似于:
a := [2][2]int{ [...]int{1,2}, [...]int{3,4} }
当声明一个 array 时,你必须在方括号内输入些内容,数字或者三个点 (...)。
3、slice
slice 与 array 接近,但是在新的元素加入的时候可以增加长度。
slice 总是指向底层的一个 array。
slice 是一个指向 array 的指针,这是其与 array 不同的地方;
slice 是引用类型,这意味着当赋值某个 slice 到另外一个变量,两个引用会指向同一个 array。
例如,如果一个函数需要一个 slice 参数,在其内对 slice 元素的修改也会体现在函数调用者中,
这和传递底层的 array 指针类似。通过:
sl := make([]int, 10)
创建了一个保存有 10 个元素的 slice。需要注意的是底层的 array 并无不同。
slice 总是与一个固定长度的 array 成对出现。其影响 slice 的容量和长度。
首先创建了 m 个元素长度的 array,
元素类型 int: var array[m]int
然后对这个 array 创建 slice: slice := array[0:n] 然后现在有:
? len(slice)== n ;
? cap(slice)== m ;
? len(array)== cap(array)== m
4、map
在 Go 中有 map 类型。map 可以认为是一个用字符串做索引的数组(在其最简单的形式下)。
下面定义了 map 类型,用于将 string(月的缩写) 转换为 int – 那个月的天数。
一般定义 map 的方法是:map[<from type>]<to type>
monthdays := map[string]int{
"Jan": 31, "Feb": 28, "Mar": 31,
"Apr": 30, "May": 31, "Jun": 30,
"Jul": 31, "Aug": 31, "Sep": 30,
"Oct": 31, "Nov": 30, "Dec": 31, ← 逗号是必须的
}
留意,当只需要声明一个 map 的时候,使用 make 的形式:
monthdays := make(map[string]int)
当在 map 中索引(搜索)时,使用方括号。
例如打印出 12 月的天数:
fmt. Printf("%d\n", monthdays["Dec"])
当对 array、slice、string 或者 map 循环遍历的时候,
range 会帮助你,每次调用,它都会返回一个键和对应的值。
year := 0
for _, days := range monthdays { ← 键没有使用,因此用 _, days
year += days
}
fmt.Printf("Numbers of days in a year: %d\n", year)
向 map 增加元素,可以这样做:
monthdays["Undecim"] = 30 ← 添加一个月
monthdays["Feb"] = 29 ← 年时重写这个元素
检查元素是否存在,可以使用下面的方式:
var value int
var present bool
value, present = monthdays["Jan"] ← 如果存在,present 则有值 true ← 或者更接近 Go 的方式
v, ok := monthdays["Jan"] ← “逗号 ok”形式
也可以从 map 中移除元素:
delete(monthdays, "Mar") ← 删除"Mar" 吧,总是下雨的月
通常来说语句 delete(m, x) 会删除 map 中由 m[x] 建立的实例。
八、函数
1、函数是构建 Go 程序的基础部件
type mytype int ← 新的类型,参阅第 5 章
func (p mytype) funcname(q int) (r,s int) { return 0,0 }
函数没有返回值:
func subroutine(in int) {
return
}
简单的将输入返回:
func identity(in int) int {
return in
}
递归函数:
func rec(i int) { if i == 10 {
return }
rec(i+1)
fmt.Printf("%d ", i)
}
这会打印:9 8 7 6 5 4 3 2 1 0。
2、作用域
定义在函数外的变量是全局的,那些定义在函数内部的变量,对于 函数来说是局部的。如果命名覆盖——一个局部变量与一个全局变量有相同的 名字——在函数执行的时候,局部变量将覆盖全局变量
package main
var a int
func main() {
a=5
println(a)
f()
}
func f() {
a := 6
println(a)
g()
}
func g() {
println(a)
}
输出内容将是:565。
局部变量仅仅在执行定义它的函数时有效
3、多值返回
函数和方法可以返回多个值
func nextInt(b []byte, i int) (int, int) {
x := 0
// 假设所有的都是数字
for ; i < len(b); i++ {
x = x*10 + int(b[i])-‘0‘
}
return x, i
}
你可以在输入的数组中扫描数字,像这样:
a := []byte{‘1‘, ‘2‘, ‘3‘, ‘4‘}
var x int
for i := 0; i < len(a); { ← 没有 i++
x, i = nextInt(a, i)
println(x)
}
4、命名返回值???
5、延迟代码???
假设有一个函数,打开文件并且对其进行若干读写。在这样的函数中,经常有 提前返回的地方。如果你这样做,就需要关闭正在工作的文件描述符。
defer 语句。
在 defer 后指定的函数会在函数退出前调用。
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
延迟的函数是按照后进先出(LIFO)的顺序执行,所以上面的代码打印: 4 3 2 1 0。
在 defer 中访问返回值
func f() (ret int) { ← ret 初始化为0
defer func() {
ret++ ← ret 增加为1
}()
return 0 ← 返回的是1 而不是0
}
6、变参
接受变参的函数是有着不定数量的参数的
func myfunc(arg ...int) {}
arg ... int 告诉 Go 这个函数接受不定数量的参数
7、函数作为值
函数也是值
匿名函数
func main() {
a := func() { ← 定义一个匿名函数,并且赋值给 a
println("Hello")
} ← 这里没有 ()
a() ← 调用函数
}
如果使用 fmt.Printf("\%T\n", a) 打印 a 的类型,输出结果是 func()。
8、回调
当函数作为值时,就可以很容易的传递到其他函数里,然后可以作为回调。
首先定义一个函数,对整数做一些 “事情”:
func printit(x int) { ← 函数无返回值
fmt.Print("%v\n", x) ← 仅仅打印
}
这个函数的标识是 func printit(int),或者没有函数名的:func(int)。
创建新的函数使用这个作为回调,需要用到这个标识:
func callback(y int, f func(int)) { ← f 将会保存函数
f(y) ← 调用回调函数 f 输入变量 y
}