介紹
在Go語言中,數組和切片都是由有序元素序列構成的數據結構。這些數據集合物在使用時非常適合處理許多相關值。它們可以使您將應該在一起的數據保持在一起,簡化您的程式碼,並同時對多個值執行相同的 Methods 和操作。
雖然Go中的數組和切片都是有序元素序列,但兩者之間有顯著差異。在Go中,數組是一種數據結構,它由在創建時定義容量的有序元素序列組成。一旦數組分配了其大小,大小就無法再進行更改。另一方面,切片是數組的可變長度版本,為使用這些數據結構的開發者提供更多靈活性。切片構成了您在其它語言中認為的數組。
考慮到這些差異,有特定的情況下您會選擇其中一個。如果您是Go的新手,確定使用它們的時機可能會令人困惑:雖然切片的多功能性使它在大多數情況下成為更適當的選擇,但有些情況下數組可以優化程式的性能。
本篇文章將深入介紹數組和切片,這將為您提供選擇這些數據類型的正確时机所需的必要信息。此外,您將回顾最容易宣告和操作數組和切片的方法。教程首先會提供對數組的描述及其操作方法,然後解釋切片及其差異。
數組
數組是一個有固定元素數量的搜集數據結構。由於數組的大小是固定的,所以數據結構只需要分配一次記憶體,而非可變長度的數據結構,必須动态分配記憶體,以便将来增大或缩小。雖然數組的固定長度可能會使其有些僵硬,但不變的記憶體分配可以提高程序的速率和性能。因此,開發者通常在數據結構永遠不需要可變元素量的 optimization 程序中使用數組。
定義數組
陣列是由在括號 [ ]
中宣告陣列的大小,然後是元素的數據類型來定義的。Go 中的陣列所有元素必須是相同的 數據類型。在數據類型後,你可以在大括號 { }
中宣告陣列元素的個別值。
以下是为阵列声明的一般模式:
注意: 重要的是要记住,每个新声明的数组都会创建一个独特的类型。所以,尽管 [2]int
和 [3]int
都具有整数元素,但它们长度的不同使它们的数据显示类型不兼容。
如果你没有宣告陣列元素的值,默认是零值,这意味着阵列的元素将是空的。对于整数,这表示为 0
,对于字符串,这表示为空字符串。
例如,以下数组 numbers
有三个整数元素还没有值:
如果你打印 numbers
,你会得到以下输出:
Output[0 0 0]
如果你想在创建数组时为元素赋值,将值放在大括号中。一个具有设定值的字符串数组看起来像这样:
你可以将数组存入一个变量并打印出来:
运行带有上述行的程序会给你以下输出:
Output[blue coral staghorn coral pillar coral elkhorn coral]
警告:當數組被打印出來時,元素之間沒有 分隔,這使得難以的分辨一個元素何時結束,另一個又何時開始。由於這個原因,有時使用 `fmt.Printf` 函數會更有幫助,該函數可以在將字符串打印到屏幕之前對它們進行格式化。提供 `%q` 動詞予此命令,指示函數將值周围的引號:`
` 這將導致以下結果:`
Output["blue coral" "staghorn coral" "pillar coral" "elkhorn coral"]
` 現在每個項目都被引用。`\n` 動詞 instructs to the formatter to add a line return at the end. `
` 有了 declarating arrays 和它們由什麼組成的一般概念,你現在可以移步至學習如何用索引號指定數組中的元素。`
` `索引數組 (和切片)` ` ` `
` 數組中的每個元素 (和切片也是) 都可以通過索引 individual。每個元素對應一個索引號,這是一個 `int` 值從索引號 `0` 開始計數上去。`
` 以下的示例將使用數組,但你也可以使用切片,它們在索引方面是 idential。`
` 对于数组 `coral`,索引分解看起来像这样:
“blue coral” | “staghorn coral” | “pillar coral” | “elkhorn coral” |
---|---|---|---|
0 | 1 | 2 | 3 |
首個元素,字符串 "blue coral"
,從索引 0
開始,切片結束於索引 3
,元素為 "elkhorn coral"
。
因為每個元素在數組或切片都有相對應的索引號碼,所以我們能夠像其他序列數據類型一樣存取和處理它們。
現在我们可以透過索引号碼來呼叫一個元素的離散形式:
Outputstaghorn coral
这个数组的索引号码从 0
到 3
,如下表所示。所以要调用任何单个元素,我们就是这样做的:
如果我们用大于 3
的索引号来调用数组 coral
,它就会超出范围,因为这是无效的:
Outputpanic: runtime error: index out of range
當索引 arrays 或 slices時,您必須始終使用正數。不像某些語言讓您可以使用負數向後索引,这样做在 Go 中會導致錯誤:
Outputinvalid array index -1 (index must be non-negative)
我们可以使用 +
Operator 来連接字符串元素和其他字符串:
OutputSammy loves blue coral
我們將索引号为 0
的字符串與字符串 "Sammy loves "
連接起來。
通過索引号碼來存取数組或切片中的每個元素,我們能够對這些元素進行操作。接下来,我们将看看如何修改特定索引处的元素。
修改元素
我們可以透過索引來修改陣列或切片中的元素,將索引命名的元素設定為不同的值。這讓我們對切片和陣列中的數據有更多控制權,並能讓我們以程式化方式操作單個元素。
如果我們想要將切片coral
中索引1
的元素字符串值從"staghorn coral"
更改為"foliose coral"
,可以这样操作:
當我們打印coral
切片時,切片將有所不同:
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral"]
現在既然您已經知道如何操作陣列或切片中的單個元素,讓我們來看一下幾個函式,這些函式將讓您在處理集合數據類型時更具彈性。
使用 len()
計算元素數量
在 Go 語言中,len()
是一個內建函式,用來幫助您與陣列和切片工作进行互動。就像對於字符串一樣,您可以通過使用len()
並將陣列或切片作為參數傳遞,來計算陣列或切片的長度。
例如,要找出coral
切片中有多少個元素,您會使用:
如果你打印出 coral
数组的长度,你会得到以下输出:
Output4
这给出了数组 coral
的长度为 4
,以 int
数据类型表示,这是正确的,因为数组 coral
有四个项目:
如果你创建一个有更多元素的整数数组,你也可以使用 len()
函数来获取其长度:
这将导致以下输出:
Output13
尽管这些示例数组中的项相对较少,但 len()
函数特别适用于确定非常大型的数组中有多少个元素。
接下来,我们将学习如何在集合数据类型中添加元素,并演示如何进行,由于数组的固定长度,向这些静态数据类型追加将导致错误。
使用 append()
追加元素
append()
是 Go 中内置的一个方法,用于向集合数据类型添加元素。但是,这个方法不能用于数组。如前所述,数组的主要区别在于其大小不能被修改。这意味着虽然你可以改变数组中元素的值,但你不能在数组定义之后使其变大或变小。
让我们考虑你的 coral
数组:
你要將項目 “"black coral"
” 加入到這個數組中。如果你嘗試使用 append() 功能來對数组進行操作,輸入:
將會出現錯誤,因為你的輸出:
Outputfirst argument to append must be slice; have [4]string
為了解決这个问题,讓我們了解更多關於切片數據型別、如何定義切片以及如何從數組轉換為切片。
切片
切片(slice)是Go語言中的一種數據型別,它是一種可變長度的有序序列,元素可以改變。由于切片的size是可变的,因此在处理需要动态扩展或收缩的数据集合时非常有用。当您需要在代码中操作可能改变大小的数据集合时,使用切片通常比使用数组更合适,因为切片能够自动管理内存分配和释放。在大多数情况下,这种可变性是值得的,即使有时可能会导致内存重新分配;与数组相比,切片提供了更多的灵活性和易用性。
當你需要存储大量的元素或者遍歷元素并进行修改时,你很可能想要使用切片。切片使得在这些元素上进行操作变得更加容易,并且允许你在不指定确切大小的前提下创建和修改数据集合。
定義一個切片
切片是通过声明数据类型前后的空方括号([]
)和花括号({}
)之间的元素来定义的。与需要方括号之间的整数来指定特定长度的数组不同,切片不需要任何内容,表示其长度可变。让我们创建一个包含字符串数据类型的切片:
当我们打印这个切片时,我们可以看到切片中的元素:
这将导致以下输出:
如果你想创建一个长度为一定值且尚未填充元素的切片,你可以使用内置的make()
函数:
Output["shark" "cuttlefish" "squid" "mantis shrimp" "anemone"]
如果打印这个切片,你会得到:
如果你想要预先分配内存以获得一定的容量,你可以在make()
中传递第三个参数:
Output["" "" ""]
这将创建一个长度为3、预先分配了5个元素的零切片。
现在你知道如何声明切片了。但是,这还没有解决我们之前遇到的coral
数组的错误。要使用append()
函数与coral
,首先需要学习如何切片数组。
切片数组
使用索引号來決定一個數组的開始和結束點,你可以调用數組的一個子區段。這稱為切片数组,你可以这样做通過创建一个用冒號隔開的索引号範圍,形式為[第一個索引:第二個索引]
。然而,值得注意的是,當切片一個 arrays時,結果是一個 slice,而不是一個 arrays。
例如,如果你想打印 coral
數组的middle部分,而不包括第一和最後一個元素,你可以這樣做:
執行一個具有此行的程序將產生以下結果:
Output[foliose coral pillar coral]
當創建一個切片,如[1:3]
,第一個數字是切片开始的(包含)位置,而第二个数字是第一个数字加上你想检索的总数:
array[starting_index : (starting_index + length_of_slice)]
在这种情况下,你从第二个元素(索引为1)开始,并检索两个元素。计算如下:
array[1 : (1 + 2)]
這就是你怎么到达這個表示法:
如果你想在数组的开始或结束处设置开始或结束点,可以在array[first_index:second_index]
语法中省略其中一个数字。例如,如果你想打印数组的前三个项目——即"blue coral"
、"foliose coral"
和"pillar coral"
,你可以这样做:
这将打印:
Output[blue coral foliose coral pillar coral]
這打印了數组的開始,在索引 3
前停止。
要包括数组的全部項目,您將使用相反的语法:
这将給下列切片:
Output[foliose coral pillar coral elkhorn coral]
本節討論了通過切片來调用個別的數目。接下来,您將會學習如何使用切片將整個數組轉換為切片。
從數組轉化為切片
如果您需要一個可變長度的數组,您可以將它轉換為切片。要将數組轉換為切片,使用您在本教程的 切片數組 步中所學的切片過程,只是這次選擇整個切片,忽略決定終點的兩個索引數字:
注意,你不能直接將变量 coral
轉換為切片,因為一旦在Go中定義了一個變量,它的類型就不能改變。要解決这个问题,你可以将整个数组的内容复制到一个新变量作为切片:
如果打印 coralSlice
,你會得到以下輸出:
Output[blue coral foliose coral pillar coral elkhorn coral]
現在,像在数组部分一樣,使用 append()
在新转换的切片上添加 black coral
元素:
这将输出包含添加元素的切片:
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral"]
我們也可以在一個 append()
Statement 中添加多個元素:
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia"]
要將兩個切片結合起來,你可以使用 append()
,但你必須擴展第二个 arguments 以 append 使用 ...
擴展符:
Output["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]
現在你已经學會如何 append 一個元素到你的切片,我们将看看如何在切片中去除此元素。
從切片中去除此元素的辦法
不像其他語言,Go 沒有内置的函数可以remove 一個元素from a slice。Items需要从slice中删除by slicing them out.
要remove一个element,you must slice out the items before that element, slice out the items after that element, then append these two new slices together without the element that you want to remove.
如果 i
是欲remove的元素索引,則此過程的格式將會如下:
From coralSlice
, let’s remove the item "elkhorn coral"
. This item is located at the index position of 3
.
Output["blue coral" "foliose coral" "pillar coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]
Now the element at index position 3
, the string "elkhorn coral"
, is no longer in our slice coralSlice
.
我們也可以用同樣的方法刪除一個範圍。假設我們想要刪除的項目不僅僅是"elkhorn coral"
,還有"black coral"
和"antipathes"
。我们可以使用範圍在表達式中達成這個目標:
這將會從切片中去掉索引3
、4
和5
:
Output["blue coral" "foliose coral" "pillar coral" "leptopsammia" "massive coral" "soft coral"]
現在你已经知道如何添加和删除元素到切片,讓我們看看如何测量切片在任何给定時間所能持有的數據量。
用cap()
测量切片容量
由於切片的长度和容量總是相同的,所以len()
方法並不是確定這種數據類型大小的最佳選擇。取而代之的是,你可以使用cap()
函数來瞭解切片能持有的數量,這是根據已經分配給切片的記憶體决定的。
注意:因為陣列的长度和容量總是相同,所以cap()
功能不會作用於陣列。
常見的使用cap()
的用法是创建一個预先設定數目元素的切片,然後programmatically填滿這些元素。這樣可以避免可能由於使用append()
向超出目前分配的空間添加元素而產生的不必要的 allocation。
我們來考慮一個情境,我們想要列印從0
到3
的數字串列。我們可以透過append()
在迴圈中完成,或者我們可以先分配切片並使用cap()
來循壞填滿值。
首先,我們可以看一下使用append()
的方法:
Output[0 1 2 3]
在這個例子中,我們創建了一個切片,然後創建了一個for
迴圈,該迴圈會迭代的四次。每一次迭代將迴圈變量i
的當前值附加到numbers
切片中。然而,這可能會導致不必要的記憶體分配,從而減緩您的程式。當向空切片添加元素時,每次呼叫append,程式會檢查切片的容量。如果添加的元素使切片超過此容量,程式將分配額外的記憶體來應對。這在您的程式中创造了額外的開銷,並可能导致執行速度變慢。
現在讓我們不使用append()
透過预分配一定長度/容量來填滿切片:
Output[0 1 2 3]
在這個例子中,我們使用make()
創建一個切片並為其預分配4
個元素。然後在迴圈中使用cap()
函數來循壞每個初始化的元素,直到達到預分配的容量。在每個迴圈中,我們將迴圈變量i
的當前值放入numbers
切片的索引中。
雖然append()
與cap()
兩種策略功能上等價,但cap()
例子的設計避免了任何額外的記憶體分配,這在使用了append()
時是需要的。
構建多維切片
你也可以定義包含其他切片作為元素的切片,每個括號内的列表都嵌套在大括號内。這樣的集合稱為多維切片。這些可以看作是表示多維坐標;例如,一個由五个切片组成的集合,每个切片有六个元素,可以代表一個水平長度為五和垂直高度為六的二维网格。
以下是一個多維切片的例子:
要訪問這個切片中的元素,我們必須使用多個索引,一個用於每個維度的構造:
在下面的代码中,我们先識別出切片在索引为1
的元素,然後指出切片在索引为0
的元素,最後指出切片在索引为0
的元素,該元素位於索引为0
的切片。这将返回以下内容:
OutputSammy
shark
以下是需要访问的其他单个元素的索引值:
當處理多維切片時,重要的是要牢記您需要參考超過一個索引號才能存取嵌套切片中的特定元素。
結論
在這個教程中,您學到了在Go語言中使用數组和切片的基础知識。您經歷了多個練習,展示數組長度固定,而切片長度可變,並發現這種差異如何影響這些數據結構的情境使用。
要继续學習Go中的數據結構,請查看我們关于Go語言中映射的理解的文章,或者探索整個如何在Go中編程系列。
Source:
https://www.digitalocean.com/community/tutorials/understanding-arrays-and-slices-in-go