var c1, c2, c3 chanint var i1, i2 int // 随机执行一个case,若所有case都堵塞,则直到有case可以通行为止 select { case i1 = <-c1: fmt.Println("received ", i1, " from c1") case c2 <- i2: fmt.Println("sent ", i2, " to c2") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { fmt.Println("received ", i3, " from c3") } else { fmt.Println("c3 is closed") } default: fmt.Println("no communication") } /* 输出: no communication */
4.4. for语句
特性:
for只带条件判断相当于while
for中使用range关键字,可以遍历顺序结构,返回key和value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
for i := 0; i < 10; i++ { fmt.Printf("i 的值为: %d\n", i) if i > 5{ break } } // 相当于c的while for numA < numB { numA++ fmt.Printf("numA 的值为: %d\n", numA) } numbers := [6]int{1, 2, 3, 5} // range关键字,可以对 slice、map、数组、字符串等进行迭代 for key, value := range numbers { fmt.Printf("第 %d 位 x 的值 = %d\n", key, value) }
// 多维数组 var array4 [4][2]int// 4行2列的二维数组,即有4行,每行有2个int
// 指向数组变量的指针 arrP := &a fmt.Printf("a 's type is %T\n", a) fmt.Printf("arrp 's type is %T\n", arrP) (*arrP)[1] = "Today"// arrP[1] = "Today" 也可以 fmt.Println(*arrP)
func copy(dst, src []T) int 将src切片的内容拷贝到dst切片中,拷贝的长度为两个slice中长度较小的长度值
func append(s []T, x ...T) []T 返回一个新切片。当原切片容量不足时,append函数会创建一个新的容量更大的底层数组,并将原切片的底层数组复制到新数组里,再追加新的值。append(dist, x, y)追加多个值(x,y…)到dist切片。append(dist, src...)将整个src切片追加到dist切片尾。
切片的多维和遍历/迭代,与数组一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// len() 和 cap() fmt.Printf("slice5 is %v, len is %d, capacity is %d\n", slice5, len(slice5), cap(slice5)) fmt.Printf("arrSlice1 is %v, len is %d, capacity is %d\n", arrSlice1, len(arrSlice1), cap(arrSlice1))
// func copy(dst, src []T) int copy(slice5, arrSlice1) // copy()函数会根据长度复制 fmt.Printf("slice5 is %v, len is %d, capacity is %d\n", slice5, len(slice5), cap(slice5))
// func append(s []T, x ...T) []T 返回一个新切片 // 当追加后,目标切片长度超过容量时,append函数会创建一个新的容量更大的底层数组,将原本数组复制到新数组中,再追加新的值 slice1 = append(slice1, 10) fmt.Printf("slice1 is %v, len is %d, capacity is %d\n", slice1, len(slice1), cap(slice1)) slice1 = append(slice1, slice2...) // 用标识符 ... 将整个切片追加到另一个切片 fmt.Printf("slice1 is %v, len is %d, capacity is %d\n", slice1, len(slice1), cap(slice1))
输出:
1 2 3 4 5
slice5 is [0 0 0], len is 3, capacity is 5 arrSlice1 is [1 2], len is 2, capacity is 4 slice5 is [1 2 0], len is 3, capacity is 5 slice1 is [10], len is 1, capacity is 1 slice1 is [10 0 1 2 3 0 6], len is 7, capacity is 8
funcmain() { // 值类型 不能使用 指针接收者 实现的方法 // Error: cannot use T literal (type T) as type I in assignment: // T does not implement I (M method has pointer receiver) var i1 I = T{"hello"} i1.M() // 指针类型 才能使用 指针接收者 实现的方法 var i2 I = &T{"hello"} i2.M() }
因此,我们通常定义类型指针来操作类型。
2.4. nil接口
如果没有为接口赋值,而调用接口中的方法,那将会报错,因为接口值为nil:
1 2 3 4 5 6 7 8 9
type I interface { M() }
funcmain() { var i I // panic: runtime error: invalid memory address or nil pointer dereference i.M() }
2.5. 空接口 - 泛型
空接口相当于C++中的泛型。格式如下:
1
interface{}
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
package main
import"fmt"
funcmain() { var i interface{} describe(i) // 输出:(<nil>, <nil>)
i = 42 describe(i) // 输出:(42, int)
i = "hello" describe(i) // 输出:(hello, string) }
funcdescribe(i interface{}) { fmt.Printf("(%v, %T)\n", i, i) // %v:变量的值,%T:变量的类型 }
2.6. 类型断言与空接口(泛型)
类型断言可以判断变量是否为该类型。格式如下:
1
t := i.(T)
若不是,将报错中断程序。如果不想中断,则使用如下格式:
1
t, ok := i.(T)
若不是,则ok值为false。
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
funcmain() { var i interface{} = "hello"
s := i.(string) fmt.Println(s)
s, ok := i.(string) fmt.Println(s, ok)
f, ok := i.(float64) fmt.Println(f, ok)
f = i.(float64) // panic: interface conversion: interface {} is string, not float64 fmt.Println(f) }
实现一个类型判断函数:
1 2 3 4 5 6 7 8 9 10
funcdo(i interface{}) { switch v := i.(type) { caseint: fmt.Printf("Twice %v is %v\n", v, v*2) casestring: fmt.Printf("%q is %v bytes long\n", v, len(v)) default: fmt.Printf("I don't know about type %T!\n", v) } }
2.7. 自定义输出格式 - Stringers 接口
Stringers接口定义如下:
1 2 3
type Stringer interface { String() string }
它允许用户自定义变量打印格式。示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
type Person struct { Name string Age int }
// type Person implements the interface Stringer func(p Person) String() string { return fmt.Sprintf("%v (%v years)", p.Name, p.Age) // 返回一个字符串 }
type admin struct { user // 嵌入 user 类型,相当于 admin 继承了 user 类型 level string }
funcmain() { // Error: cannot use promoted field user.name in struct literal of type admin // Error: cannot use promoted field user.email in struct literal of type admin // ad := admin{ // name: "john", // email: "qq.com", // level: "1", // }
type admin struct { user name string// 覆盖 user 类型中的 name 属性 level string }
funcmain() { // cannot use promoted field user.name in struct literal of type admin // cannot use promoted field user.email in struct literal of type admin ad := admin{ user: user{ name: "john", email: "qq.com", }, name: "tom", level: "1", }