1.map
map 是引用類型的,如果聲明沒有初始化值,默認是nil。空的切片是可以直接使用的,因為他有對應的底層數組,空的map不能直接使用。需要先make之后才能使用。
//1, 聲明map 默認值是nil
var m1 map[key_data_type]value_data_type
聲明 變量名稱 map[key的數據類型]value的數據類型
//2,使用make聲明
m2:=make(map[key_data_type]value_data_type)
//3,直接聲明并初始化賦值map方法
m3:=map[string]int{"語文":89,"數學":23,"英語":90}
1.1 map 使用
- 插入以及更新語法:map[key]=value
- 刪除map中key對應的鍵值對數據 語法: delete(map, key)
- 訪問語法 map[key]
//遍歷map
for key, val := range map1 {fmt.Println(key, val)
}
1.2 map底層原理
源代碼解析
struct Hmap
{
uint8 B; // 可以容納2^B個項
uint16 bucketsize; // 每個桶的大小
byte *buckets; // 2^B個Buckets的數組
byte *oldbuckets; // 前一個buckets,只有當正在擴容時才不為空
};struct Bucket
{
uint8 tophash[BUCKETSIZE]; // hash值的高8位....低位從bucket的array定位到bucket
Bucket *overflow; // 溢出桶鏈表,如果有
byte data[1]; // BUCKETSIZE keys followed by BUCKETSIZE values
};
// BUCKETSIZE是用宏定義的8,每個bucket中存放最多8個key/value對, 如果多于8個,那么會申請一個新的bucket,overflow指向它
- Bucket中key/value的放置順序,是將keys放在一起,values放在一起。
- 擴容使用的是增量擴容:擴容會建立一個大小是原來2倍的新的表,將舊的bucket搬到新的表中之后,并不會將舊的bucket從oldbucket中刪除,而是加上一個已刪除的標記。當hash表擴容之后,需要將那些舊的pair重新哈希到新的table上,這個工作是逐步的完成(在insert和remove時每次搬移1-2個pair)
查找過程
- 根據key計算出hash值。
- 如果存在old table, 首先在old table中查找,如果找到的bucket已經evacuated,轉到步驟3。 反之,返回其對應的value。
- 在new table中查找對應的value。
插入過程分析 - 根據key算出hash值,進而得出對應的bucket。
- 如果bucket在old table中,將其重新散列到new table中。
- 在bucket中,查找空閑的位置,如果已經存在需要插入的key,更新其對應的value。
- 根據table中元素的個數,判斷是否grow table。
- 如果對應的bucket已經full,重新申請新的bucket作為overbucket。
將key/value pair插入到bucket中。
2.流程控制
- 我們的程序的執行正常是由上到下逐行執行,叫做 順序結構 。
- 程序中為了滿足某種條件的時候才會執行的結構,叫做選擇結構(if、 switch)。
- 當滿足條件時候循環反復執行多次的代碼, 叫做 循環結構(for)
2.1 if語句
if 布爾表達式{//布爾條件為true時候執行代碼
}if 布爾表達式 {//條件成立執行代碼
}else{//條件不成立執行代碼
}if 布爾表達式 {//布爾條件為true時候執行代碼
}else if 布爾表達式2{//布爾條件為flase時候執行代碼
}else{//上面都不成立執行代碼
}
特殊寫法:Go語言中可以在if之后,條件判斷之間再加上一段執行語句,執行的結果再用作后面的條件判斷。(先執行語句,再判斷條件)
if a :=1; a==1
{}
2.2 switch分支語句
if 中判斷條件只能為bool類型,但是switch中條件可以為其他類型,case的值必須是唯一的,因為只能進入一個case語句塊。
switch 中 break 和fallthrough
break 直接跳出整個switch語句塊
fallthrough 當前case執行完了,繼續執行下面的case
2.3 for 循環語句
語法: for init; condition;post{ }
init 初始化 只執行一次
condition bool類型 執行條件 如果滿足繼續執行后面的循環體 如果不滿足 則終止執行
{} 循環體
post 表達式 將在循環體執行結束之后執行
break:跳出當前循環,如果后面break后面帶標簽,則跳到標簽處
continue: 中止當前循環,進入下一循環
goto: 和break加標簽用法一樣
3. 值傳遞與引用傳遞
golang中的變量可以分為以下兩種類型
- 值類型:int、float、string、bool、array、struct
- 引用類型: slice、pointer、map、chan 等
值類型傳遞的是數值本身,被修改不會影響原來的值。
引用類型傳遞的是內存地址,被修改時會影響原來的值。
4. 深拷貝和淺拷貝
淺拷貝復制過來的是內存地址,操作的是同一對象,但是深拷貝是新建一個對象,并且將源對象的內容通通復制一份。
使用深拷貝數據函數: copy(目標切片,數據源)