go語言教程之淺談數組和切片的異同

Hello ,各位小夥伴你們好,我是小棧君,上次分享咱們講到了Go語言關於項目工程結構的管理,本期的分享咱們來說解一下關於go語言的數組和切片的概念、用法和區別。java

在go語言的程序開發過程當中,咱們避免不了數組和切片。關於他們的用法和區別卻使得有的小夥伴感受困惑。因此小棧君這裏也概括和總結了關於數組和切片的乾貨幫助小夥伴進行理解。算法

數組的定義

數組是具備相同惟一類型的一組已編號且長度固定的數據項序列,這種類型能夠是任意的原始類型例如整形、字符串或者自定義類型。數組

相對於去聲明 number0, number1, ..., number99 的變量,使用數組形式 numbers[0], numbers[1] ..., numbers[99] 更加方便且易於擴展。數據結構

數組元素能夠經過索引(位置)來讀取(或者修改),索引從 0 開始,第一個元素索引爲 0,第二個索引爲 1,以此類推。app

圖片描述

整體來說的話數組就是同一種類型的固定長度的序列。函數

在go語言中數組的定義是很簡單的。區塊鏈

圖片描述

如圖所示,咱們定義了一個長度爲2的數組,在數組定義的過程當中,系統已經對這個數組進行了初始化並分配了空間。因此咱們若是想要進行賦值能夠經過數組名加上下標的方式進行賦值。可是值得注意的一點是咱們並不能進行數組的超長處理。這一點有別於java的數組定義,java的定長數組添加值後若是對於超出的值會有自動擴容功能。測試

圖片描述

可是在go語言中並無方法來進行增刪改查值,只有經過下標的方式,因此咱們若是進行了越界處理編譯都會進行報錯。因此才入門的小夥伴們須要注意一下哦。數組的下標在數組的合法範圍以外就會出發訪問越界,會有panic出現。因此小棧君也是經過了一個實例給你們說明一下,由於編譯可能會不經過,因此咱們巧妙的避開編譯器的編譯進行數組的越界操做說明。大數據

圖片描述

固然須要值得注意的一點是,數組的長度也是數組類型的一部分,所以var a [2]int 和 var b [3] int 是兩個不一樣的類型。指針

知識點來了,在go語言中的數組是屬於值類型傳遞,當咱們傳遞一個數組到一個方法中,改變副本的值並不會修改到本來數組的值。因此獲得的數組仍是原來的樣子。

圖片描述

所以若是咱們要對數組進行值的修改的話,就只有進行指針操做啦~。

圖片描述

切片的概念

在go語言中數組中長度不能夠更改,因此在實際的應用環境中並非很是實用,因此Go語言衍生出了一種靈活性強和功能更強大的內置類型,即爲切片。

與上面所講的數組相比,切片的長度是不固定的,而且切片是能夠進行擴容。切片對象很是小,是由於它是隻有3個字段的數據結構:一個是指向底層數組的指針,一個是切片的長度,一個是切片的容量。這3個字段,就是Go語言操做底層數組的元數據,有了它們,咱們就能夠任意的操做切片了。

固然,切片做爲數組的引用,因此切片屬因而引用類型,各位小夥伴可千萬要記住了哦。在切片的使用過程中,咱們能夠經過遍歷數組的方式進行對於切片的遍歷,咱們也能夠內置方法len對數組或切片進行長度的計算。

固然咱們也能夠對切片的容量進行計算,以前有講過Go語言有豐富的內置庫提供給咱們使用,因此咱們也能夠cap內置函數進行容量的計算。多個切片若是表示同一個數組的片斷,它們能夠共享數據;所以一個切片和相關數組的其餘切片是共享存儲的,相反,不一樣的數組老是表明不一樣的存儲。數組其實是切片的構建塊。

圖片描述

圖片描述

上面的例子小棧君分別用數組和切片進行了測試,咱們能夠看到數組的容量一旦肯定後就沒法進行更改,當咱們的切片進行初始化,初始的容量是2,此時切片的容量和長度都是2,可是我經過內置的append方法進行了切片的增長。此時的切片的容量和長度都是4。此時咱們並不能肯定切片內置擴容的機制,可是隱約猜想是倍增。

言歸正傳,爲了測試一下切片的擴容機制,因此小棧君又進行了切片的增長,此時,細心的小夥伴應該發現,此次小棧君一次性增長了兩個元素在一個append裏面,由於這是append方法是一個可變長度的傳值。這也是一個小知識點哦。

若是切片的底層數組,沒有足夠的容量時,就會新建一個底層數組,把原來數組的值複製到新底層數組裏,再追加新值,這時候就不會影響原來的底層數組了。

append目前的算法是:容量小於1000個時,老是成倍的增加,一旦容量超過1000個,增加因子設爲1.25,也就是說每次會增長25%的容量。

以後咱們發現切片的容量和長度發生了變化,若是說上次容量的擴張是4是咱們猜想的倍數擴容方式,那麼此次咱們就實錘了他的擴容機制就是倍增。並且在Go語言的容量和長度不同,因此咱們也能夠得出結論,就是在 0 <= len(arry) <= cap(slice)。

在咱們聲明好切片後咱們可使用new或是make方法對切片進行初始化,固然小棧君也試着嘗試證實切片若是沒有進行初始化是會panic的。結果並無出現。由於若是slice沒有初始化,它僅僅至關於一個nil,長度和容量都爲0,並不會panic。

圖片描述

小棧君也考慮到多是由於沒有內置增長方法或是沒有報錯僅僅只是由於我後面利用對Carry數組的切割進行賦值的緣故。因此不甘心又作了一次嘗試,定義好相應的切片後直接使用append方法,結果以下:

圖片描述

咱們一樣能夠經過上述的例子瞭解到切片的下標是左閉右開區間,由於咱們carry數組的內容如上圖所示, 咱們最終獲得的結果是IT乾貨棧,下標來說的話是屬於1。因此咱們獲得的結論和事實是同樣的。對於切片咱們也有不少用法,以下圖所示:

圖片描述

下圖是Python中對於切片的操做,而且Python中的數組更爲靈活,在後面我爲你們分享Python教程的時候會詳細分享哦。

圖片描述

切片的初始化

對於切片的初始化咱們能夠make方法和new方法

圖片描述

new(T) 爲每一個新的類型T分配一片內存,初始化爲 0 而且返回類型爲*T的內存地址:這種方法 返回一個指向類型爲 T,值爲 0 的地址的指針,它適用於值類型如數組和結構體;它至關於 &T{}。

make(T) 返回一個類型爲 T 的初始值,它只適用於3種內建的引用類型:切片、map 和 channel。

拷貝

由於在go語言的數組是屬於值傳遞,以前的方法也證明了這一點,在方法傳遞值的時候系統會進行拷貝一份副本進行傳遞,若是須要改變的值的話就須要使用指針。可是在使用切片處理的時候,由於切片屬於引用傳遞,因此go語言有內置的函數copy方法進行值的拷貝。

圖片描述

上述的一個例子能夠綜合說明幾點問題了,最開始咱們定義了一個切片而且容量是2,內容是1和2,咱們一樣定義了切片b可是並無作初始化處理。直接使用copy操做。使用copy操做的時候,小棧君也複製了源碼出來,第一個是咱們的數據源,第二個參數傳遞咱們的目標源。直接使用的話咱們能夠從結果看出並無成功。

因此接下來小棧君又進行了初始化操做。這裏舉例的目的是提醒各位,在操做切片的時候沒有初始化就至關於nil,最好是進行切片的初始化操做。在早期go語言的版本中,沒有初始化切片會直接報錯。接下來我又進行了再一次的複製操做而且打印出他們的地址和容量、長度。能夠看出進行切片的拷貝是不會進行切片的擴容處理。並且他們分別指向了不一樣的地址說明拷貝成功。

好了,今天的分享就到這啦,若是你喜歡個人分享,麻煩你點擊一個好看或贊,我是小棧君,不按期分享IT乾貨,包括但不限於區塊鏈、大數據、Python、go、等系列專題。但願與你共同成長。咱們下期再見啦,拜了個拜~

本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索