藝多不壓身,學習一下最近蠻火的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個字符
*/
}
