數組,是用來存儲集合資料的。這種場景非常多,我們編碼的過程中,都少不了要讀取或者存儲資料。當然除了數組之外,我們還有切片、Map映射等資料結構可以幫我們存儲資料,但是數組是它們的基礎。
内部實作
要想更清晰地了解數組,我們先得了解它的内部實作。數組是長度固定的資料類型,必須存儲一段相同類型的元素,而且這些元素是連續的。我們這裡強調固定長度,可以說這是和切片最明顯的差別。
數組存儲的類型可以是内置類型,比如整型或者字元串;也可以是自定義的資料結構。因為是連續的,是以索引比較好計算,是以我們可以很快地索引數組中的任何資料。
這裡的索引,一直都是0、1、2、3這樣的,因為其元素類型相同。我們也可以使用反射,擷取類型占用大小,進行移位,擷取相應的元素。這部分在說到反射的時候,我們再講。
聲明和初始化
數組的聲明和初始化,和其他類型差不多。聲明的原則是:
指明存儲資料的類型。
存儲元素的數量,也就是數組長度。
以上我們聲明了一個數組<code>array</code>,但是我們還沒有對他進行初始化,這時候數組<code>array</code>裡面的值,是對應元素類型的零值。也就是說,現在這個數組是 5 個 0 ,這和我們Java不一樣,Java裡是null。
數組一旦聲明後,其元素類型和大小都不能變了,如果還需要存儲更多的元素怎麼辦?那麼隻能通過建立一個新的數組,然後把原來數組的資料複制過去。
剛剛聲明的數組已經被預設的元素類型零值初始化了,如果我們再次進行初始化怎麼做呢,可以采用如下辦法:
這兩步比較繁瑣,Go為我們提供了<code>:=</code>操作符,可以讓我們在建立數組的時候直接初始化。
這種簡短變量聲明的方式不僅适用于數組,還适用于任何資料類型,這也是Go語言中常用的方式。
有時候我們更懶,連數組的長度都不想指定。不過沒有關系,使用…代替就好了,Go會自動推導出數組的長度。
假如我們隻想給索引為 1 和 3 的數組初始化相應的值,其他都為 0 怎麼做呢,直接的辦法有:
還有一種更好的辦法,上面講預設初始化為零值,那麼我們就可以利用這個特性,隻初始化索引 1 和 3 的值:
使用數組
數組的通路非常簡單,通過索引即可,操作符為[]。因為記憶體是連續的,是以索引通路的效率非常高。
修改數組中的一個元素也很簡單:
如果我們要循環列印數組中的所有值,一個傳統的就是常用的for循環:
不過大部分時候,我們都是使用for rang循環:
這兩段示例代碼,輸出的結果是一樣的。
同樣類型的數組是可以互相指派的,不同類型的不行,會編譯錯誤。那麼什麼是同樣類型的數組呢?Go語言規定,必須是長度一樣,并且每個元素的類型也一樣的數組,才是同樣類型的數組。
指針數組和數組本身差不多,隻不過元素類型是指針。
這樣就建立了一個指針數組,并且為索引 1 和 3 都建立了記憶體空間,其他索引是指針的零值<code>nil</code>,這時候我們要修改指針變量的值也很簡單,如下即可:
以上需要注意的是,隻可以給索引 1 和 3 指派,因為隻有它們配置設定了記憶體,才可以指派。如果我們給索引 0 指派,運作的時候,會提示無效記憶體或者是一個nil指針引用。
要解決這個問題,我們要先給索引 0 配置設定記憶體,然後再進行指派修改。
函數間傳遞數組
在函數間傳遞變量時,總是以值的方式。如果變量是個數組,那麼就會整個複制,并傳遞給函數。如果數組非常大,比如長度 100 多萬,那麼這對記憶體是一個很大的開銷。
通過上面的例子,可以看到,數組是複制的,原來的數組沒有修改。我們這裡是 5 個長度的數組還好,如果有幾百萬怎麼辦,有一種辦法是傳遞數組的指針,這樣,複制的大小隻是一個數組類型的指針大小。
這是傳遞數組的指針的例子,會發現數組被修改了。是以這種情況雖然節省了複制的記憶體,但是要謹慎使用,因為一不小心,就會修改原數組,導緻不必要的問題。
這裡注意,數組的指針和指針數組是兩個概念,數組的指針是<code>*[5]int</code>,指針數組是<code>[5]*int</code>,注意<code>*</code>的位置。
針對函數間傳遞數組的問題,比如複制問題,比如大小僵化問題,都有更好的解決辦法,這個就是切片,它更靈活
本文轉自 baby神 51CTO部落格,原文連結:http://blog.51cto.com/babyshen/1913252,如需轉載請自行聯系原作者