Go 其三 Map与String
艺多不压身,学习一下最近蛮火的Go语言,整理一下笔记。相关Code和笔记也放到了Git上,传送门。
MAP
Map 声明
m := map[string]int{"one":1, "two":2, "three":3} m1 := map[string]int{} m1["one"] = 1 m2 := make(map[string]int, 10/*Initial Capacity*/) //为什么不初始化len? 对于切片 s := make([]int, 3, 5) 会指定len并给默认的0值,但语义上Map其实没办法指定默认值的,因此没有len.
Map元素的访问
与其他主要变成语言的差异
当访问的Key不存在时,仍会返回零值,不能通过返回nil来判断元素是否存在,可以用如下方式判断
if v,ok:=m1[3];ok{ t.Logf("Key 3's value is %d", v) } else { t.Log("Key 3 is not existing.") }
其中ok为bool值,当值存在时,ok的值为true
Map遍历
m := map[string]int{"one":1, "two":2, "three":3} for k,v := range m { t.Log(k,v) }
附上测试代码:
package my_map import "testing" func TestInitMap(t *testing.T){ m1:=map[int]int{1:1,2:4,3:9} t.Log(m1[2]) t.Logf("len m1=%d", len(m1)) m2:=map[int]int{} m2[4]=16 t.Logf("len m2=%d", len(m2)) m3:=make(map[int]int,10) t.Logf("len m3=%d", len(m3)) //cap()是不能用于求map的capacity的. 下面的code会报错:invalid argument m3 (type map[int]int) for capgo //t.Logf("len m3=%d", cap(m3)) } func TestAccessNotExistingKey(t *testing.T){ m1:=map[int]int{} t.Log(m1[1]) m1[2] = 0 t.Log(m1[2]) //以上的输出结果为 /* TestAccessNotExistingKey: map_test.go:21: 0 TestAccessNotExistingKey: map_test.go:23: 0 */ // 但实际上m1[1]是不存在的值,m1[2]是存在但值为0,这是两种情况 事实上当value不存在时Go会给赋一个默认值 //好处是这样不会有空指针异常,坏处是需要额外判断一下是不存在还是本身就是零值。具体判断方式如下: if v,ok:=m1[3];ok{ t.Logf("Key 3's value is %d", v) } else { t.Log("Key 3 is not existing.") } m1[3] = 0 if v,ok:=m1[3];ok{ t.Logf("Key 3's value is %d", v) } else { t.Log("Key 3 is not existing.") } } func TestTraveMap(t *testing.T){ m1:=map[int]int{1:1,2:4,3:9} for key,value := range m1{ t.Log(key,value) } }
Map与工厂模式
Map的value可以是一个方法
与Go的Dock type接口方式一起,可以方便的实现单一方法对象的工厂模式
实现Set
Go的内置集合中没有Set实现,可以map[type]bool
- 元素的唯一性
- 基本操作
添加元素
判断元素是否存在
删除元素
元素个数
附上代码:
package map_ext import "testing" func TestMapWithFunValue(t *testing.T){ m:=map[int]func(op int)int{} m[1] =func(op int) int {return op} m[2] =func(op int) int {return op * op} m[3] =func(op int) int {return op * op * op} t.Log(m[1](2),m[2](2),m[3](2)) } func TestMapForSet(t *testing.T){ mySet:=map[int]bool{} //1) 添加元素 mySet[1] = true n:=1 //2) 判断元素是否存在 if mySet[n] { t.Logf("%d is existing", n) } else { t.Logf("%d is not existing", n) } //3) 删除元素类似 delete(mySet, 1) //4) 元素个数 t.Log(len(mySet)) // 删除元素后显示 1 is not existing if mySet[n] { t.Logf("%d is existing", n) } else { t.Logf("%d is not existing", n) } }
字符串
字符串
与其他主要变成语言的差异
- Go中string是数据类型,不是引用或指针类型,所以它的零值是""而不是null
- string是只读的byte slice, len函数返回的实际上是string所包含的byte数,与具体string包含多少字符是不同的
- string的byte数组可以存放任何数据
Unicode 和 UTF8
- Unicode 是一种字符集(code point)
- UTF8是unicode的存储实现(转换为字节序列的规则)
编码与存储
字符 “中”
Unicode 0x4E2D
UTF-8 0XE4B8AD
string/[]byte [0xE4,0xB8,0xAD]
常用字符串函数
- strings包 https://golang.org/pkg/strings/
- strconv包 https://golang.org/pkg/strconv/
附上代码:
package string_test import "testing" func TestString(t *testing.T){ var s string t.Log(s) t.Log(len(s)) s = "\xE4\xB8\xA4" //即使是不可显示的字符也可以存储,如"\xE4\xBB\xA5"将显示乱 t.Log(s) t.Log(len(s)) //输出结果为3,但其实对应的是一个中文字符 ‘两’ // string是不可以变的byte slice,因此不能给它赋值 a := "Hello" //a[1] = '3' // 报错:cannot assign to a[1]go t.Log(a) b := "中" t.Log(len(b)) //是byte数 c := []rune(b) //rune能够取出字符串中的unicode,这是Go的一个内置机制 t.Log(len(c)) t.Logf("中 unicode %x", c[0]) t.Logf("中 UTF8 %x", s) //以上四个log输出的结果分别为: /* TestString: string_test.go:21: 3 TestString: string_test.go:23: 1 TestString: string_test.go:24: 中 unicode 4e2d TestString: string_test.go:25: 中 UTF8 e4b8a4 */ } func TestStringToRune(t *testing.T){ s:= "中华人民共和国" for _,c:=range s{ t.Logf("%[1]c %[1]d",c) } /*d 以上运行结果为 TestStringToRune: string_test.go:38: 中 20013 TestStringToRune: string_test.go:38: 华 21326 TestStringToRune: string_test.go:38: 人 20154 TestStringToRune: string_test.go:38: 民 27665 TestStringToRune: string_test.go:38: 共 20849 TestStringToRune: string_test.go:38: 和 21644 TestStringToRune: string_test.go:38: 国 22269 注意这里看代码可能有些别扭,这里的‘%[1]c %[1]d’ 其实意思是 以%c的格式格式化第1个字符 和 以%d的格式格式化第1个字符 */ }