搜尋
首頁系統教程Linux在 Go 中使用切片的容量和長度的技巧

在 Go 中使用切片的容量和長度的技巧

Mar 20, 2024 pm 02:36 PM
linuxlinux教程紅帽linux系統linux指令linux認證紅帽linuxlinux視頻

在 Go 中使用切片的容量和长度的技巧

#快速測試 - 下面的程式碼輸出什麼?

vals := make([]int, 5)
for i := 0; i 
<p>如果你猜的是 [0 0 0 0 0 0 1 2 3 4],那你是對的。 </p>
<p>如果你在測驗中做錯了,你也不用擔心。這是在過渡到 Go 語言的過程中相當常見的錯誤,在這篇文章中,我們將說明為什麼輸出不是你預期的,以及如何利用 Go 的細微差別來使你的程式碼更有效率。 </p>
<div style="font-size: 14pt; color: white; background-color: black; border-left: red 10px solid; padding-left: 14px; margin-bottom: 20px; margin-top: 20px;"><strong>切片 vs 陣列</strong></div>#<p>在 Go 中同時有陣列(array)和切片(slice)。這可能令人困惑,但一旦你習慣了,你會喜歡上它。請相信我。 </p>
<p>切片和數組之間存在許多差異,但我們要在本文中重點介紹的內容是數組的大小是其類型的一部分,而切片可以具有動態大小,因為它們是圍繞數組的封裝。 </p>
<p>這在實踐中意味著什麼?那麼假設我們有數組 val a [10]int。此數組具有固定大小,且無法變更。如果我們呼叫 len(a),它總是會回傳 10,因為這個大小是類型的一部分。因此,如果你突然需要在數組中超過 10 個項,則必須建立一個完全不同類型的新對象,例如 val b [11]int,然後將所有值從 a 複製到 b。 </p>
<p>在特定情況下,含有集合大小的陣列是有價值的,但一般而言,這不是開發人員想要的。相反,他們希望在 Go 中使用類似於數組的東西,但是隨著時間的推移,它們能夠隨時增長。一個粗略的方式是建立一個比它需要大得多的數組,然後將數組的子集視為數組。下面的程式碼就是個例子。 </p>
<pre class="brush:php;toolbar:false">var vals [20]int
for i := 0; i 
<p>在程式碼中,我們有一個長度為20 的數組,但由於我們只使用一個子集,程式碼中我們可以假定數組的長度是5,然後在我們向數組中添加一個新的項之後是6 。 </p>
<p>這是(非常粗略地說)切片是如何工作的。它們包含一個具有設定大小的數組,就像我們前面的例子中的數組一樣,它的大小為 20。 </p>
<p>它們也追蹤程式中使用的陣列的子集 - 這就是 append 屬性,它類似於上一個例子中的 subsetLen 變數。 </p>
<p>最後,一個切片還有一個 capacity,類似於前面範例中我們的陣列的總長度(20)。這是很有用的,因為它會告訴你的子集在無法容納切片數組之前可以增長的大小。當發生這種情況時,需要指派一個新的數組,但所有這些邏輯都隱藏在 append 函數的後面。 </p>
<p>簡而言之,使用 append 函數組合切片給我們一個非常類似於陣列的類型,但隨著時間的推移,它可以處理更多的元素。 </p>
<p>我們再來看前面的例子,但這次我們將使用切片而不是陣列。 </p>
<pre class="brush:php;toolbar:false">var vals []int
for i := 0; i 
<p>我們仍然可以像數組一樣存取我們的切片中的元素,但是透過使用切片和 append 函數,我們不再需要考慮背後數組的大小。我們仍然可以透過使用 len 和 cap 函數來計算這些東西,但是我們不用擔心太多。簡潔吧? </p><div style="font-size: 14pt; color: white; background-color: black; border-left: red 10px solid; padding-left: 14px; margin-bottom: 20px; margin-top: 20px;"><strong>回到測試</strong></div>
<p>記住這一點,讓我們回顧前面的測試,看下什麼出錯了。 </p>
<pre class="brush:php;toolbar:false">vals := make([]int, 5)
for i := 0; i 
<p>當呼叫 make 時,我們允許最多傳入 3 個參數。第一個是我們指派的類型,第二個是類型的“長度”,第三個是類型的“容量”(這個參數是可選的)。 </p>
<p>透過傳遞參數 make([]int, 5),我們告訴程式我們要建立一個長度為 5 的切片,在這種情況下,預設的容量與長度相同 - 本例中是 5。 </p>
<p>雖然這可能看起來像我們想要的那樣,這裡的重要區別是我們告訴我們的切片,我們要將「長度」和「容量」設為5,假設你想要在初始的5 個元素之後加入新的元素,我們接著呼叫append 函數,那麼它會增加容量的大小,並且會在切片的最後添加新的元素。 </p>
<p>如果在程式碼中加入一條 Println() 語句,你可以看到容量的變化。 </p>
<pre class="brush:php;toolbar:false">vals := make([]int, 5)
fmt.Println("Capacity was:", cap(vals))
for i := 0; i 
<p>最後,我們最終得到 [0 0 0 0 0 0 1 2 3 4] 的輸出而不是希望的 [0 1 2 3 4]。 </p>
<p>要如何修復它呢?好的,這有幾種方法,我們將講解兩種,你可以選取任何一種在你的場景中最有用的方法。 </p>
<div style="font-size: 14pt; color: white; background-color: black; border-left: red 10px solid; padding-left: 14px; margin-bottom: 20px; margin-top: 20px;"><strong>直接使用索引寫入而不是 append</strong></div><p>#第一種修復是保留 make 呼叫不變,並且明確地使用索引來設定每個元素。這樣,我們就得到如下的程式碼:</p>
<pre class="brush:php;toolbar:false">vals := make([]int, 5)
for i := 0; i 
<p>在這種情況下,我們設定的值恰好與我們要使用的索引相同,但是你也可以獨立追蹤索引。 </p>
<p>例如,如果你想要取得 map 的鍵,你可以使用下面的程式碼。 </p>
<pre class="brush:php;toolbar:false">package main

import "fmt"

func main() {
  fmt.Println(keys(map[string]struct{}{
    "dog": struct{}{},
    "cat": struct{}{},
  }))
}

func keys(m map[string]struct{}) []string {
  ret := make([]string, len(m))
  i := 0
  for key := range m {
    ret[i] = key
    i
  }
  return ret
}

這樣做很好,因為我們知道我們傳回的切片的長度將與 map 的長度相同,因此我們可以用該長度初始化我們的切片,然後將每個元素分配到適當的索引中。這種方法的缺點是我們必須追蹤 i,以便了解每個索引要設定的值。

這就讓我們引出了第二種方法…

使用 0 作為你的長度並指定容量

與其追蹤我們要新增的值的索引,我們可以更新我們的 make 調用,並在切片類型之後提供兩個參數。第一個,我們的新切片的長度將被設定為 0,因為我們還沒有添加任何新的元素到切片中。第二個,我們新切片的容量將被設定為 map 參數的長度,因為我們知道我們的切片最終會添加許多字串。

這會如前面的例子那樣仍舊會在背後建立相同的數組,但是現在當我們呼叫 append 時,它會將它們放在切片開始處,因為切片的長度是 0。

package main

import "fmt"

func main() {
  fmt.Println(keys(map[string]struct{}{
    "dog": struct{}{},
    "cat": struct{}{},
  }))
}

func keys(m map[string]struct{}) []string {
  ret := make([]string, 0, len(m))
  for key := range m {
    ret = append(ret, key)
  }
  return ret
}
如果 append 處理它,為什麼我們還要擔心容量?

接下來你可能會問:「如果 append 函數可以為我增加切片的容量,那我們為什麼要告訴程式容量呢?」

事實是,在大多數情況下,你不必擔心這太多。如果它讓你的程式碼變得更複雜,只需用 var vals []int 初始化你的切片,然後讓 append 函數處理接下來的事。

但這種情況是不同的。它並不是聲明容量困難的例子,實際上這很容易確定我們的切片的最後容量,因為我們知道它將直接映射到提供的 map 中。因此,當我們初始化它時,我們可以聲明切片的容量,並免於讓我們的程式執行不必要的記憶體分配。

如果要查看額外的記憶體分配情況,請在 Go Playground 上執行以下程式碼。每次增加容量,程式都需要做一次記憶體分配。

package main

import "fmt"

func main() {
  fmt.Println(keys(map[string]struct{}{
    "dog": struct{}{},
    "cat": struct{}{},
    "mouse": struct{}{},
    "wolf": struct{}{},
    "alligator": struct{}{},
  }))
}

func keys(m map[string]struct{}) []string {
  var ret []string
  fmt.Println(cap(ret))
  for key := range m {
    ret = append(ret, key)
    fmt.Println(cap(ret))
  }
  return ret
}

現在將此與相同的程式碼進行比較,但具有預先定義的容量。

package main

import "fmt"

func main() {
  fmt.Println(keys(map[string]struct{}{
    "dog": struct{}{},
    "cat": struct{}{},
    "mouse": struct{}{},
    "wolf": struct{}{},
    "alligator": struct{}{},
  }))
}

func keys(m map[string]struct{}) []string {
  ret := make([]string, 0, len(m))
  fmt.Println(cap(ret))
  for key := range m {
    ret = append(ret, key)
    fmt.Println(cap(ret))
  }
  return ret
}

在第一個程式碼範例中,我們的容量從0 開始,然後增加到1、 2、 4, 最後是8,這意味著我們必須分配5 次數組,最後一個容納我們切片的陣列的容量是8,這比我們最終需要的要大。

另一方面,我們的第二個例子開始和結束都是相同的容量(5),它只需要在 keys() 函數的開頭分配一次。我們還避免了浪費任何額外的內存,並返回一個能放下這個數組的完美大小的切片。

不要過度優化

#如前所述,我通常不鼓勵任何人做這樣的小優化,但如果最後大小的效果真的很明顯,那麼我強烈建議你嘗試為切片設定適當的容量或長度。

這不僅有助於提高程式的效能,還可以透過明確說明輸入的大小和輸出的大小之間的關係來幫助澄清你的程式碼。

總結

本文並不是對切片或陣列之間差異的詳細討論,而是簡要介紹了容量和長度如何影響切片,以及它們在方案中的用途。


以上是在 Go 中使用切片的容量和長度的技巧的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:Linux就该这么学。如有侵權,請聯絡admin@php.cn刪除
互聯網在Linux上運行嗎?互聯網在Linux上運行嗎?Apr 14, 2025 am 12:03 AM

互聯網運行不依賴單一操作系統,但Linux在其中扮演重要角色。 Linux廣泛應用於服務器和網絡設備,因其穩定性、安全性和可擴展性受歡迎。

Linux操作是什麼?Linux操作是什麼?Apr 13, 2025 am 12:20 AM

Linux操作系統的核心是其命令行界面,通過命令行可以執行各種操作。 1.文件和目錄操作使用ls、cd、mkdir、rm等命令管理文件和目錄。 2.用戶和權限管理通過useradd、passwd、chmod等命令確保系統安全和資源分配。 3.進程管理使用ps、kill等命令監控和控制系統進程。 4.網絡操作包括ping、ifconfig、ssh等命令配置和管理網絡連接。 5.系統監控和維護通過top、df、du等命令了解系統運行狀態和資源使用情況。

使用Linux別名提高自定義命令快捷方式的生產率使用Linux別名提高自定義命令快捷方式的生產率Apr 12, 2025 am 11:43 AM

介紹 Linux是一個強大的操作系統,由於其靈活性和效率,開發人員,系統管理員和電源用戶都喜歡。但是,經常使用長而復雜的命令可能是乏味的

Linux實際上有什麼好處?Linux實際上有什麼好處?Apr 12, 2025 am 12:20 AM

Linux適用於服務器、開發環境和嵌入式系統。 1.作為服務器操作系統,Linux穩定高效,常用於部署高並發應用。 2.作為開發環境,Linux提供高效的命令行工具和包管理系統,提升開發效率。 3.在嵌入式系統中,Linux輕量且可定制,適合資源有限的環境。

在Linux上掌握道德黑客的基本工具和框架在Linux上掌握道德黑客的基本工具和框架Apr 11, 2025 am 09:11 AM

簡介:通過基於Linux的道德黑客攻擊數字邊界 在我們越來越相互聯繫的世界中,網絡安全至關重要。 道德黑客入侵和滲透測試對於主動識別和減輕脆弱性至關重要

如何學習Linux基礎知識?如何學習Linux基礎知識?Apr 10, 2025 am 09:32 AM

Linux基礎學習從零開始的方法包括:1.了解文件系統和命令行界面,2.掌握基本命令如ls、cd、mkdir,3.學習文件操作,如創建和編輯文件,4.探索高級用法如管道和grep命令,5.掌握調試技巧和性能優化,6.通過實踐和探索不斷提陞技能。

Linux最有用的是什麼?Linux最有用的是什麼?Apr 09, 2025 am 12:02 AM

Linux在服務器、嵌入式系統和桌面環境中的應用廣泛。 1)在服務器領域,Linux因其穩定性和安全性成為託管網站、數據庫和應用的理想選擇。 2)在嵌入式系統中,Linux因其高度定制性和高效性而受歡迎。 3)在桌面環境中,Linux提供了多種桌面環境,滿足不同用戶需求。

Linux的缺點是什麼?Linux的缺點是什麼?Apr 08, 2025 am 12:01 AM

Linux的缺點包括用戶體驗、軟件兼容性、硬件支持和學習曲線。 1.用戶體驗不如Windows或macOS友好,依賴命令行界面。 2.軟件兼容性不如其他系統,缺乏許多商業軟件的原生版本。 3.硬件支持不如Windows全面,可能需要手動編譯驅動程序。 4.學習曲線較陡峭,掌握命令行操作需要時間和耐心。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。