【Golang】快速複習指南QuickReview(二)——切片slice

切片Slice

在上一篇【Golang】快速複習指南QuickReview(一)——字符串string的字符串翻轉代碼實現中,提到了切片,切片在golang中是很重要的數據類型。說到切片,就不得不提數組,但是數組的長度是固定的並且數組長度屬於類型的一部分,所以數組有很多的侷限性。而切片(Slice)是可變長度的,其實切片是基於數組類型做了一層封裝,所以切片會指向一個底層數組。切片新增元素,當切片指向的底層數組能夠容納,則直接新增元素,當底層數組不能容納新增的元素時,切片就會自動按照一定的策略進行“擴容”,此時該切片指向的底層數組就會更換。

切片有兩個非常重要的屬性,長度(len),容量(cap),前者是切片已經包含的元素數量,後者是切片的首指針(第一個元素)指向的底層數組索引至底層數組最後一個元素的長度。

1.C#的泛型集合List

根據切片的特性,博主類比的是C#中泛型集合,也會有類似長度與容量等屬性,包括自動擴容,但是博主並不清楚擴容算法是否一致,有興趣的朋友可以自行查閱。

//實例化 初始化
List<string> ls = new List<string> { "北京", "上海", "廣州", "深圳" };

//輸出容量與長度
Console.WriteLine($"the capacity of citylist is {ls.Capacity},and the length of citylist is {ls.Count}");

//新增元素
ls.Add("成都");

//再次輸出容量與長度
Console.WriteLine($"the capacity of citylist is {ls.Capacity},and the length of citylist is {ls.Count}");

//刪除元素
ls.Remove("成都");

//再次輸出容量與長度
Console.WriteLine($"the capacity of citylist is {ls.Capacity},and the length of citylist is {ls.Count}");

//遍歷元素
foreach (string city in ls)
{

}
the capacity of citylist is 4,and the length of citylist is 4
the capacity of citylist is 8,and the length of citylist is 5
the capacity of citylist is 8,and the length of citylist is 4

另外在C#中還提供了很多很多擴展方法來操作泛型集合,這裏提一些常用的。

//添加多個元素
public void AddRange(IEnumerable<T> collection);

//刪除所有
public void Clear();

//按條件刪除
public int RemoveAll(Predicate<T> match);

//按索引進行範圍刪除
public void RemoveRange(int index, int count);

//遍歷操作
public void ForEach(Action<T> action);

//判斷是否存在某元素
 public bool Contains(T item);

//按條件判斷是否存在
public bool Exists(Predicate<T> match);

//按條件查找指定元素
public List<T> FindAll(Predicate<T> match);

//翻轉集合
public void Reverse();

//轉換數組
public T[] ToArray();

2.Golang中的切片

切片沒有在C#中的泛型集合那麼方便,具有一些硬性條件,例如分配空間,操作函數也少,但是也順便減少了記憶量,記住下面的一些常規操作,基本就能看懂源碼裏對切片進行的相關操作。

2.1 初始化-新增-複製

//定義不初始化-這個定義不初始化的稱爲-零值切片
var citySlice0 []string

//定義且初始化
var citySlice1 = []string{}
var citySlice2 = []string{"北京", "上海", "廣州", "深圳"}

//make定義並初始化
citySlice := make([]string, 4, 10)
fmt.Printf("the citySlice is %v\n", citySlice)
//輸出容量和長度
fmt.Printf("the capacity of citySlice is %v,and the length of citySlice is %v \n", cap(citySlice), len(citySlice))

//新增元素
citySlice = append(citySlice, "北京", "上海", "廣州", "深圳")
fmt.Printf("the citySlice is %v\n", citySlice)
fmt.Printf("the capacity of citySlice is %v,and the length of citySlice is %v \n", cap(citySlice), len(citySlice))

//新增元素
citySlice = append(citySlice, "成都", "武漢")
fmt.Printf("the citySlice is %v\n", citySlice)
fmt.Printf("the capacity of citySlice is %v,and the length of citySlice is %v \n", cap(citySlice), len(citySlice))

//var聲明的零值切片最簡單的方式便是通過append函數直接使用,無需初始化
var intSliceA []int
intSliceA = append(intSliceA, 1, 2, 3)
fmt.Printf("the intSliceA is %v \n", intSliceA)//[1 2 3]

//切片是引用類型 簡單的賦值就出現如下結果
intSliceB := intSliceA
intSliceB[0] = 0
fmt.Printf("the intSliceA is %v \n", intSliceA) //[0,2,3]

//爲了不影響賦值操作,只要複製切片才能達到預期的效果, 但是把一個切片複製給另一個切片,目的切片需要分配空間
intSliceC := make([]int, 4, 5)
copy(intSliceC, intSliceA)
fmt.Printf("the intSliceC is %v \n", intSliceC) //[0 2 3 0]  第4個元素0,是因爲分配了空間,都是零值
intSliceC[0] = 10
fmt.Printf("the intSliceA is %v \n", intSliceA) //[0 2 3]
fmt.Printf("the intSliceC is %v \n", intSliceC)	//[10 2 3 0]
the citySlice is [   ]
the capacity of citySlice is 10,and the length of citySlice is 4 
the citySlice is [    北京 上海 廣州 深圳]
the capacity of citySlice is 10,and the length of citySlice is 8
the citySlice is [    北京 上海 廣州 深圳 成都 武漢]
the capacity of citySlice is 10,and the length of citySlice is 10

the intSliceA is [1 2 3]
the intSliceA is [0 2 3]
the intSliceC is [0 2 3 0]
the intSliceA is [0 2 3]
the intSliceC is [10 2 3 0]

2.2 切

切片之所以叫切片,着重點在切

“數組上切,就成了切片,在切片上切,就成了切切片(#.#),當然不是,還是叫切片。”

//the intSliceC is [10 2 3 0]

//從索引1切到最後
intSliceD := intSliceC[1:]
fmt.Printf("the intSliceD is %v \n", intSliceD) // [2 3 0]

//從索引1切到索引2,按照數學知識就是左閉右開[1,3)
intSliceE := intSliceC[1:3]
fmt.Printf("the intSliceE is %v \n", intSliceE) //[2 3]

//從索引0切到n-1  0,1,2
intSliceF := intSliceC[:3]
fmt.Printf("the intSliceF is %v \n", intSliceF) //[10 2 3] 

//再次驗證長度與容量
fmt.Printf("the capacity of intSliceF is %v,and the length of intSliceF is %v \n", cap(intSliceF), len(intSliceF))

//
fmt.Printf("the intSliceC is %v \n", intSliceC)	//[10 2 3 0]
the intSliceD is [2 3 0]
the intSliceE is [2 3]
the intSliceF is [10 2 3] 
the capacity of intSliceF is 5,and the length of intSliceF is 3
the intSliceC is [10 2 3 0]

2.3 刪除

golang是沒有提供切片的直接刪除函數,但是是可以利用內置的append()函數

func append(slice []Type, elems ...Type) []Type

ps:參數中使用可變參數... Type,是類似於C#中可變參數params T[] xC#內部是轉換成數組處理,Golang內部轉換爲了切片。有那麼一點差別,就是如果參數傳切片,後面需要加...,其餘用法與C#一致

intSliceC = append(intSliceC[:1], intSliceC[2:]...) 
fmt.Printf("the intSliceC is %v \n", intSliceC) // [10 2 0]
fmt.Printf("the capacity of intSliceC is %v,and the length of intSliceC is %v \n", cap(intSliceC), len(intSliceC))
the intSliceC is [10 2 0]
the capacity of intSliceC is 5,and the length of intSliceC is 3

2.4 判斷切片是否爲空

只能使用len函數,不能使用nil

len(s) == 0

2.5 遍歷

s := []int{1, 3, 5}

for i := 0; i < len(s); i++ {
    fmt.Println(i, s[i])
}
for index, value := range s {
    fmt.Println(index, value)
}
0 1
1 3
2 5
0 1
1 3
2 5

再次強調:這個系列並不是教程,如果想系統的學習,博主可推薦學習資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章