for语句
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。
for key, value := range oldMap {
newMap[key] = value
}
//如果只想读取 key,格式如下:
for key := range oldMap
//如果只想读取 value,格式如下:
for _, value := range oldMap
switch语句
用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。
还可以用来替代任何的if-else语句,switch后直接接大括号,case相当于if
:相当于{}
default相当于else,:相当于{}
array
数组在go中很少使用,因为它的长度是固定的,和数组对应的类型是Slice(切片),它是可以增长和收缩的动态序列,slice功能也更灵活
演示代码及运行结果
package main
import "fmt"
func main() {
var a [5]int
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
}
//get: 0
//len: 5
//[1 2 3 4 5]
//2d: [[0 1 2] [1 2 3]]
slice
Slice · Go语言圣经 (studygolang.com)
package main
import "fmt"
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
}
slice的底层确实引用一个数组对象
一个slice由三个部分构成:指针、长度和容量
- 长度对应slice中元素的数目
- 长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置
- 内置的len和cap函数分别返回slice的长度和容量
一个中文对应多个字符串长度
Map
K对应的key必须是支持==比较运算符的数据类型,所以map可以通过测试key是否相等来判断是否已经存在。
虽然浮点数类型也是支持相等运算符比较的,但是将浮点数用做key类型则是一个坏的想法,正如第三章提到的,最坏的情况是可能出现的NaN和任何浮点数都不相等。
对于V对应的value数据类型则没有任何的限制。
nil值map
map类型的零值是nil,也就是没有引用任何哈希表。
var ages map[string]int
fmt.Println(ages == nil) // "true"
fmt.Println(len(ages) == 0) // "true"
map上的大部分操作,包括查找、删除、len和range循环都可以安全工作在nil值的map上,它们的行为和一个空的map类似。但是向一个nil值的map存入元素将导致一个panic异常:
ages["carol"] = 21 // panic: assignment to entry in nil map
在向map存数据前必须先创建map。
创建一个map的方法
//创建一个空的map的两种方式
ages := make(map[string]int)
ages := map[string]int{}
//用map字面值的语法创建map,同时还可以指定一些最初的key/value
ages := map[string]int{
"marco": 19,
"charlie": 34,
}
//相当于
ages := make(map[string]int)
ages["marco"] = 19
ages["charlie"] = 34
map相关操作
//通过key访问value
ages["marco"] = 20
fmt.Println(ages["alice"]) // "20"
//删除元素
delete(ages, "marco") // remove element ages["marco"]
map中的元素并不是一个变量,因此我们不能对map的元素进行取址操作,原因是map可能随着元素数量的增长而重新分配更大的内存空间,从而可能导致之前的地址无效。
通过key作为索引下标来访问map将产生两个值。
- 第一个是value,如果key在map中是存在的,那么将得到与key对应的value;如果key不存在,那么将得到value对应类型的零值。
- 第二个是一个布尔值,用于报告元素是否真的存在,用于区别一个已经存在的0,和不存在而返回零值的0。
age, ok := ages["bob"]
if !ok { /* "bob" is not a key in this map; age == 0. */ }
//或者结合起来用
if age, ok := ages["bob"]; !ok { /* ... */ }
遍历
在golang中可以使用range风格的for循环对map中全部的k-v遍历。
for name, age := range ages {
fmt.Printf("%s\t%d\n", name, age)
}
遍历的顺序是随机的,每一次遍历的顺序都不相同。
如果要按顺序遍历key/value对,我们必须显式地对key进行排序,可以使用sort包的Strings函数对字符串slice进行排序。
import "sort"
var names []string
for name := range ages {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
fmt.Printf("%s\t%d\n", name, ages[name])
}