十一:陣列和切片
不允許混合不同型別的元素
a:slice可以向後擴充套件,不可以向前擴充套件
b:s[i]不可以超越len(s),向後擴充套件不可以超越底層陣列cap(s)
c:新增元素時如果超越cap,系統會重新分配更大的底層陣列
d:由於值傳遞的關係,必須接收append的返回值
e:s = append(s,val)
1、陣列的宣告
var a [3]int 宣告一個長度為3的整型陣列,陣列中的所有元素都被自動賦值為陣列型別的零值
a := [3]int{12,13,19}
a := [...]int{12,24,25}
陣列的大小是型別的一部分,陣列不能調整大小
2、陣列是值型別
go中的陣列是值型別而不是引用型別
3、陣列的長度
len(a)
4、使用range迭代陣列
for i, v := range a {
}
for _, v := range a {
}
5、多維陣列
a := [2][2]string{
{'dd', "dsd"},
{"sc", "xs"},
}
6、切片
a:建立一個切片
a := [5]int{23,343,43,43,43} var b []int = a[1:4]
c := []int{5,3,5}
b:切片的修改
切片所做的更改會反映在陣列中
c:切片的長度和容量
切片的容量是從建立切片索引開始的底層陣列中元素數
切片可以重置容量
d:使用make建立一個切片
make( []T, len, cap)[]T i := make([]int, 5, 5)
e:追加切片元素
1、切片是動態的,使用append可以將元素追加到切片上 append(s[]T,x...T)[]T
2、當新的元素被新增到切片時,會建立一個新的陣列。現有的陣列被複制到這個新的陣列中,並返回這個新陣列的新切片中。
3、切片型別的零值是nil,一個nil切片的長度和容量都是0。可以使用append函式將值追加到nil切片
4、...運算子可以將一個切片新增到另一個切片中 food := append(veggies, fruits...)
f:切片的函式傳遞
當切片作為引數傳遞給函式時,函式內所做的更改也會在函式外可見
g:切片的記憶體優化
切片持有對底層陣列的引用。只要切片在記憶體中,陣列就不能被垃圾回收。假設有一個非常大的陣列,只要處理一小部分。
解決方法L:使用copy函式生成一個切片的副本複製程式碼
十二:可變函式引數
func find(num int, nums ...int){
}
1、可變引數函式的工作原理是把可變引數轉換為一個新的切片 ,可以不給可變引數nums傳入任何引數,
nums是一個長度和容量為0的nil切片
2、將切片直接傳入可變引數函式 在切片後面加... 切片將直接傳入函式,不再建立新的切片
find(89,nums...)複製程式碼
十三:maps
map是在go中將值與鍵關聯的內建型別,通過相應的鍵可以獲取到值
1、如何建立map map必須使用make函式初始化
通過向map函式傳入鍵和值的型別,可以建立map。make(map[type of key]type of value)是建立map的語法
personSalary := make(map[string]int) 鍵是string型別,值是int型別
2、給map新增元素
personSalary["steve"] = 1233
personSalary := map[string]int{
"steve":1200,
"jam":1500,
}
personSalary["mike"] = 9000
3、獲取map中的元素
a: 獲取一個不存在的元素,會返回int型別的零值0
b: 要想知道map中到底是不是存在這個key,ok為true,表示key存在
value, ok := map[key]
c:遍歷map中所有的元素需要用for range迴圈
for key, value := range personSarlary{
fmt.Printf(key,value)
}
使用for range遍歷map時,不保證每次執行程式獲取的元素順序相同
4、刪除map中的元素
刪除map中key的語法是delete(map,key)
5、獲取map的長度
len(personSalary)
6、map是引用型別
和slices類似,map也是引用型別。
7、map的相等性
map之間不能使用 == 操作符判斷, == 只能用來檢查map是否為nil複製程式碼
十四:字串
字串在go語言中有著自己特殊的實現,是一個位元組切片。go中的字串是相容Unicode編碼的,使用UTF-8進行編碼
1、單獨獲取字串的每一個位元組
a:%x格式限定符用於指定16進位制編碼
for i:= 0;i < len(s);i++{
}
b:%c格式用於列印字串中的字元 在uft-8編碼中,一個程式碼點可能會佔用超過一個位元組的空間,可以使用rune解決
2、rune
rune是int32的別稱,在go中,rune表示一個程式碼點,程式碼無論佔用多少個位元組,都可以用一個rune表示
func printChars(s string){
runes := []rune(s)
for i:= 0;i < len(runes);i++{
fmt.Printf("%c",runes[i])
}
}
3、字串的for range迴圈
for index, rune := range s{
}
4、用位元組切片構造字串
byteSlice := []byte{0x43, 0x61, 0x66, 0xC3, 0xA9}
str := string(byteSlice)
fmt.Println(str)
用utf-8編碼的16進位制位元組,暑促是Cafe 16進位制換成10進位制也一樣
5、rune切片構造字串 runeSlice := []rune{0x0053,0x0065} //16進位制的Unicode程式碼點
6、字串的長度
uft8 package包中的func RuneCountInString(s string) (n int)方法用來獲取字串的長度,這個方法傳入一個字串
然後返回字串中的rune的數量
7、字串是不可變的
a:go中的字串是不可變的,一旦一個字串被建立,那麼它將無法被修改
b:為了修改字串,可以把字串轉化為一個rune切片。然後這個切片可以進行任何想要的改變,然後轉化為一個字串
func mutate(s []rune) string {
s[0] = 'a'
return string(s)
}
func main() {
h := "hello"
fmt.Println(mutate([]rune(h)))
}複製程式碼
十五:指標
- 要改變內容必須使用指標接收者
- 結構過大也考慮使用指標接收者
- 一致性:如果有指標接收者,最好都是指標接收者
- 值接收者是go語言特有
- 值/指標接收者均可接收值/指標
1、指標的宣告
a:指標的變數型別為 *T,該指標指向一個T型別的變數
b := 255 var a *int = &b
&操作符用於獲取變數的地址
b:指標的零值是 nil
2、指標的解引用
指標的解引用可以獲取指標所指向的變數的值。將a解引用的語法是 *a
3、向函式傳遞指標引數
change(val *int){
*val = 55
}
4、不要向函式傳遞陣列的指標,而應該使用切片
a:把一個指向陣列的指標傳遞給這個函式 a[x]是(*a)[x]的簡寫形式
b:最好使用切片修改陣列
5、go不支援指標運算複製程式碼
十六:結構體
1、結構體的宣告
type Employee struct {
firstName string
lastName string
age int
}
匿名結構體:
var employee struct {
fistName, lastName string
age int
}
2、建立匿名結構體
emp3 := struct {
firstName, lastName string
age, salary int
}{
firstName: "And",
lastName: "Nik",
age: 31,
salary: 50000,
}
3、結構體的零值
4、結構體的指標
emp8 := &Employee{"Sam", "And", 55, 6000}
訪問欄位:(*emp8).firstName
可以使用emp8.firstName來代替顯式的解引用 (*emp8).firstName
5、匿名欄位
建立結構體時,欄位可以只有型別,而沒有欄位名。這樣的欄位稱為匿名欄位
//含有兩個匿名欄位
type Person struct {
string
int
}
雖然匿名欄位沒有名稱,但其實匿名欄位的名稱就預設為它的型別
6、巢狀結構體
type Address struct {
city,state string
}
type Person struct {
name string
age int
address Address
}
var p = Person
person.name = "nav"
p.age = 50
p.address = Address {
city: 'Chi'
state: "s"
}
7、提升欄位
如果結構體中有匿名的結構體型別欄位,則結構體內的欄位就稱為提升欄位。提升欄位就像是屬於
外部結構體一樣,可以直接訪問
8、匯出結構體和欄位
如果結構體名稱以大寫字母開頭,則是其他包可以訪問的匯出型別。如果結構體裡的欄位首字母大寫,
也能被其他包訪問
9、結構體相等性
a: 結構體是值型別,如果它的每一個欄位都是可比較的,則該結構體也是可比較的。
如果兩個結構體變數的對應欄位相等,則這兩個變數也是相等的
b:如果結構體包含不可比較的欄位,則結構體變數也不可比較
type image struct {
data map[int]int
}複製程式碼
十七:方法
1:方法就是一個函式,在func這個關鍵字和方法名中間加入裡一個特殊的接受器型別。
a: 接收器可以是結構體或非結構體型別,可以在方法內部訪問'
type Employee struct {
name string
}
func (e Employee) display() {
}
b:方法呼叫
emp1 := Employee{
name: 'Sam'
}
emp1.display()
2、為什麼有了函式還需要方法
a:go不是純粹的物件導向程式語言,而且go不支援類,基於型別的方法是一種實現和類相似行為的途徑
b:相同名字的方法可以定義在不同的型別,而相同名字的函式是不被允許的
3、指標接收器和值接收器
a:指標接收器的方法內部的改變對於呼叫者是可見的,值接收器不是這樣
b:指標接收器使用:
1:對方法內部的接收器所做的改變應該對呼叫者可見時
2:結構體有很多欄位,在方法內部使用結構體作為值接收器需要拷貝整個結構體;使用
指標接收器,只會傳遞一個指標到方法的內部使用
4、匿名欄位的方法
屬於結構體的匿名欄位的方法可以被直接呼叫,就像方法屬於定義匿名欄位的結構體一樣
5、方法中使用值接收器與在函式中使用值引數
a:一個函式有一個值引數,只能接受一個值引數
b:一個方法有一個值接收器,可以接受值接收器和指標接收器
6、方法職工使用指標接收器與在函式中使用指標引數
函式中只接受指標,指標接收器的方法可以使用值接收器和指標接收器
7、在非結構體的方法上
a:為了在一個型別上定義一個方法,方法的接收器型別定義和方法的定義應該在同一個包中
func (a int) add(b int){
// 嘗試把一個add方法新增到內建的型別int,不被允許,因為add方法的定義和int型別的定義不
//再一個包中
}
type myInt int
func (a myInt) add(b myInt) myInt{
//這樣是可以的
}複製程式碼
十八:介面一
1、介面
a:在物件導向的領域裡:介面定義一個物件的行為
b:在go語言中,介面就是方法簽名的集合。當一個型別定義裡介面中的所有方法,稱它實現裡介面
介面指定裡一個型別應該具有的方法,並由該型別決定如何實現這些方法
2、介面的宣告與實現
a:其他語言如java,要求一個類使用implement關鍵字,顯示的宣告該類實現類介面
b:在go中一個型別包含類介面中宣告的所有方法,就隱式的實現類介面
3、介面的實際用途
4、介面的內部表示
5、空介面
沒有包含方法的介面稱為空介面,空介面表示為interface{}.空介面沒有方法,所有型別都實現了空介面
6、型別斷言
型別斷言用於提取介面的底層值。在語法i.(T)中,介面i的具體型別是T。
使用v,ok := i.(T)不會報錯
7、型別選擇
a:型別選擇用於將介面的具體型別與很多case語句所指定的型別進行比較
switch i.(type){
case string:
fmt.Printtf('d')
case int:
fmt.Printf('x')
}
b:可以將一個型別和介面相比較。如果一個型別實現類介面,那麼該型別與其實現的介面可以互相比較複製程式碼
十九:介面二
1、實現介面:指標接受者與值接受者
a:使用值接受者的方法,可以用值來呼叫,也能用指標呼叫
b:對於使用指標接受者的方法,用一個指標或者一個可取得地址的值呼叫都是合法的。
但介面中儲存的具體值不能取到地址
2、實現多個介面
3、介面的巢狀
go語言沒有提供繼承機制,可以通過巢狀其他介面建立一個新介面
4、介面的零值
介面的零值是nil,對於值為nil的介面。其底層值和具體型別都為nil,呼叫它的方法會產生異常。複製程式碼
二十:併發入門
1、併發是指立即處理多個任務的能力
go語言原生支援併發,go使用go協程和通道來處理併發
2、並行是指同時處理多個任務
並行並不一定會加快執行速度,因為並行執行的元件之間可能需要相互通訊複製程式碼