Go:學習筆記兼吐槽(1)html
Go:學習筆記兼吐槽(3)json
Golang 中,數組是值類型。數組
var arr [10]int
var arr1 [3]int = [3]int{1, 2, 3}
var arr2 = [3]int{4, 5, 6}
var arr3 = [...]int{7, 8, 9}
var arr4 = [...]int{1: 100, 2: 200, 3: 300}
基本語法:app
for index, value := range 數組變量{
}
其中:index
爲數組下標,value
是該下標位置的值。函數
長度是數組類型的一部分,就是說數組不能夠脫離長度而存在。聽起來不太明白,咱們來看下面的一個示例就明白了,這真的是一個大坑。post
假設,咱們如今要寫一個排序函數,C# 中,咱們會這樣定義:學習
public void Sort(int[] array)
{
}
可是,在 Golang 中,這是不行的。ui
func main() {
var arr [3]int = [3]int{1, 2, 3}
Sort(arr)
}
func Sort(array []int){
}
Sort(arr)
這句編譯就會報錯:cannot use arr (type [3]int) as type []int in argument to Sort。由於 Sort
函數的參數 array []int
是一個切片,不是數組,將數組做爲參數傳給 Sort
就會報類型不匹配。url
若是必定須要以數組做爲參數傳遞,Sort
的參數必須定義成數組,就是帶上長度:
func Sort(array [3]int){
}
這麼定義這函數還有啥用?吐槽一萬字…
雖然有切片能夠用來實現咱們的功能,可是,數組就變得有點雞肋了。
切片是引用類型,相似於 C# 中的 list
。內部維護一個數組,當追加元素超出切片容量時,切片自動擴容。(跟 list
是同樣的機制。)
var arr []int
//方法一:
var arr1 [5]int = [5]int{1, 2, 3, 4, 5}
slice1 := arr1[1: 3] //這裏的使用跟 Python 很像
//方法二:
var slice2 []int = make([]int, 5, 10)
//方法三:
var slice3 []int = []int{1, 2, 3, 4, 5}
使用 make
初始化切片,make
的三個參數依次爲:切片數據類型,切片長度,切片容量。
//方法一:追加一個或多個同類型
var slice1 []int = make([]int, 5, 10)
slice1 = append(slice1, 100, 200)
fmt.Printf("%v\n", slice1)
//方法二:追加切片(只能是切片,不能夠是數組)
var slice2 []int = []int{1, 2, 3, 4, 5}
slice1 = append(slice1, slice2...) // 三個點不能少
fmt.Printf("%v", slice1)
append
函數也很搞笑,其返回值必須賦值給一個切片,不然編譯都過不了。若是一個切片調用append
追加元素後,又賦值給了本身(咱們通常也是這麼用的),則切片的地址不會發生改變(除非發生了擴容)。若是 切片 1 調用append
後賦值給了 切片 2,則 切片 1 保持未追加前的原樣不變,另生成一個新的切片賦給 切片 2。
示例:
var slice1 []int = make([]int, 5, 10)
fmt.Printf("%v %p\n", slice1, &slice1) // [0 0 0 0 0] 0xc000004460
slice1 = append(slice1, 100)
fmt.Printf("%v %p\n", slice1, &slice1) // [0 0 0 0 0 100] 0xc000004460
slice2 := append(slice1, 200)
fmt.Printf("%v %p\n", slice1, &slice1) // [0 0 0 0 0 100] 0xc000004460
fmt.Printf("%v %p\n", slice2, &slice2) // [0 0 0 0 0 100 200] 0xc0000044e0
就是字典。
var m map[int]string
// 方式一:使用 make 函數
m := make(map[int]string, 10)
// 方式二:直接賦值
m := map[int]string{
1: "張三",
2: "李四",
}
make
方法的第一個參數是 map 的數據類型,第二個參數是初始容量。
注意,若是是方式二直接賦值,最後一個 key-value 後面也要加逗號。
delete(map, key)
參數:
Golang 中 map 沒有相似其餘語言中的 clear
方法,若是要一次性刪除所有元素,可遍歷 map 逐一刪除,或者從新 make
一下使其指向一個新的內存空間。
val, finded := m[1]
if finded{
fmt.Println(val)
}
只能用 for-range 遍歷
for k, v := range m{
fmt.Printf("%v: %v\n", k, v)
}
type 結構體名稱 struct{
field1 type
field2 type
}
type Person struct{
Name string
Age int
}
// 方式一:
p1 := Person{}
p1.Name = "Tom"
p1.Age = 10
// 方式二
p2 := Person{"Jerry", 5}
// 方式三
p3 := Person{Name: "張三", Age: 30}
// 或
p3 := Person{
Name: "張三",
Age: 30, // 注意這裏要加逗號,不然會被默認加上分號
}
// 方式一:
var person1 *Person = new(Person)
(*person1).Name = "Tom"
(*person1).Age = 10
fmt.Println(*person1)
// 方式二:
person2 := new(Person)
person2.Name = "Tom"
person2.Age = 10
fmt.Println(*person2)
// 方式三:
var person3 *Person = &Person{"Jerry", 5}
fmt.Println(*person3)
這三種方式定義的都是結構體指針,由於是指針,因此給字段賦值的標準方式應該是方式一的寫法,可是 Go 的設計者爲了程序員使用方便,給出了一個語法糖,使 (*person1).Name = "Tom"
簡化爲 person1.Name = "Tom"
,即方式二的寫法,編譯時,會自動加上取值運算。而方式三的寫法能夠直接賦值。
struct 的每一個字段上能夠定義一個標籤(tag),該標籤能夠經過反射機制獲取,最多見的使用場景就是序列化和反序列化。
type Person struct{
Name string `json:"name"`
Age int `json:"age"`
}
p := Person{"張三", 30}
jsonStr, err := json.Marshal(p)
if err == nil {
fmt.Println(string(jsonStr)) // {"name":"張三","age":30}
}
爲了簡化數據類型定義,Golang 支持自定義數據類型。
基本語法:
type 自定義數據類型名 數據類型 // 至關於起了一個別名
示例:
type myint int //這時 myint 就等價於 int,可是 Go 會認爲他們仍是兩個類型
type mySum func(int, int) int //這時 mySum 就等價於一個函數類型
自定義數據類型跟原類型雖然在咱們的理解上是同樣的,可是 Golang 會認爲它們是兩種不一樣的數據類型。這致使這兩種類型是沒法直接進行比較的,必須強轉。