記錄Go的循環遍歷使用小坑
golang#1欄位分享給大家的循環遍歷使用小坑 ,希望對需要的朋友有所幫助!
在Golang的流程控制中,迴圈語句有for和range兩種。
for語句
1.for 賦值表達式; 關係式表達式或邏輯表達式; 賦值表達式{ }
for i := 0; i < 10; i++ {}
2.for 關係式或邏輯運算式{ }
n := 10for n > 0 { n--}
#3.for { }
for { fmt.Println("hello world") } // 等价于 // for true { // fmt.Println("hello world") // }
str := "abc" for i, char := range str { fmt.Printf("%d => %s\n", i, string(char)) } for i := range str { //只有一个返回值 fmt.Printf("%d\n", i) } nums := []int{1, 2, 3} for i, num := range nums { fmt.Printf("%d => %d\n", i, num) } kvs := map[string]string{"a": "apple", "b": "banana"} for k, v := range kvs { fmt.Printf("%s => %s\n", k, v) } for k := range kvs { //只有一个返回值 fmt.Printf("%s\n", k) } // 输出结果 // 0 => a // 1 => b // 2 => c // 0 // 1 // 2 // 0 => 1 // 1 => 2 // 2 => 3 // a => apple // b => banana // a // b
場景一,使用循環迭代器的變數
先來看一個明顯的錯誤:func main() { var out []*int for i := 0; i < 3; i++ { // i := i out = append(out, &i) } fmt.Println("值:", *out[0], *out[1], *out[2]) fmt.Println("地址:", out[0], out[1], out[2]) } // 输出结果 // 值: 3 3 3 // 地址: 0xc000012090 0xc000012090 0xc000012090
分析
out是一個整數指標數組變量,在for循環中,聲明了一個
i變量,每次循環將
i的位址追加到
out切片中,但每次追加的其實都是
i變量,因此我們追加的是一個相同的位址,而該位址最終的值是3。
正確做法解開程式碼中的註解
// i := i,每次迴圈時都重新建立一個新的
i變數。
再看一個比較隱密的錯誤:
func main() { a1 := []int{1, 2, 3} a2 := make([]*int, len(a1)) for i, v := range a1 { a2[i] = &v } fmt.Println("值:", *a2[0], *a2[1], *a2[2]) fmt.Println("地址:", a2[0], a2[1], a2[2]) } // 输出结果 // 值: 3 3 3 // 地址: 0xc000012090 0xc000012090 0xc000012090
分析大多數人就是在
range這裡給變數賦值的時候踩坑,因為比較隱秘,其實情況和上面的一樣,
range在遍歷值類型時,其中的
v是一個局部變量,只會聲明初始化一次,之後每次循環時重新賦值覆寫前面的,所以給
a2[i]賦值的時候其實都是同一個位址
&v,而
v最終的值為
a1最後一個元素的值,也就是3。
正確做法①
a2[i]賦值時傳遞原始指針,即
a2[i] = &a1[i] ②建立臨時變數
t := v;
a2[i] = &t③閉包(與②原理一樣),
func (v int) { a2[i] = &v }(v)
更隱密的還有:
func main() { var out [][]int for _, i := range [][1]int{{1}, {2}, {3}} { out = append(out, i[:]) } fmt.Println("Values:", out)}// 输出结果// [[3] [3] [3]]
i[:]總是被本次遍歷的值所覆蓋
#場景二,在循環體內使用goroutinesfunc main() {
values := []int{1, 2, 3}
wg := sync.WaitGroup{}
for _, val := range values {
wg.Add(1)
go func() {
fmt.Println(val)
wg.Done()
}()
}
wg.Wait()}// 输出结果// 3// 3// 3
登入後複製
func main() { values := []int{1, 2, 3} wg := sync.WaitGroup{} for _, val := range values { wg.Add(1) go func() { fmt.Println(val) wg.Done() }() } wg.Wait()}// 输出结果// 3// 3// 3
分析對於主協程來講,循環是很快就跑完的,而這個時候各個協程可能才開始跑,此時
val的值已經遍歷到最後一個了,所以各協程都輸出了
3。 (如果遍歷資料龐大,主協程遍歷耗時較久的話,goroutine的輸出會根據當時候的
val的值,所以每次的輸出結果不一定相同的。)
解決方法①使用臨時變數
for _, val := range values { wg.Add(1) val := val go func() { fmt.Println(val) wg.Done() }()}
for _, val := range values { wg.Add(1) go func(val int) { fmt.Println(val) wg.Done() }(val)}
以上是記錄Go的循環遍歷使用小坑的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在Go中安全地讀取和寫入檔案至關重要。指南包括:檢查檔案權限使用defer關閉檔案驗證檔案路徑使用上下文逾時遵循這些準則可確保資料的安全性和應用程式的健全性。

如何為Go資料庫連線配置連線池?使用database/sql包中的DB類型建立資料庫連線;設定MaxOpenConns以控制最大並發連線數;設定MaxIdleConns以設定最大空閒連線數;設定ConnMaxLifetime以控制連線的最大生命週期。

可以透過使用gjson函式庫或json.Unmarshal函數將JSON資料儲存到MySQL資料庫中。 gjson函式庫提供了方便的方法來解析JSON字段,而json.Unmarshal函數需要一個目標類型指標來解組JSON資料。這兩種方法都需要準備SQL語句和執行插入操作來將資料持久化到資料庫中。

GoLang框架與Go框架的差異體現在內部架構與外部特性。 GoLang框架基於Go標準函式庫,擴充其功能,而Go框架由獨立函式庫組成,以實現特定目的。 GoLang框架更靈活,Go框架更容易上手。 GoLang框架在效能上稍有優勢,Go框架的可擴充性更高。案例:gin-gonic(Go框架)用於建立RESTAPI,而Echo(GoLang框架)用於建立Web應用程式。

後端學習路徑:從前端轉型到後端的探索之旅作為一名從前端開發轉型的後端初學者,你已經有了nodejs的基礎,...

FindStringSubmatch函數可找出正規表示式匹配的第一個子字串:此函數傳回包含匹配子字串的切片,第一個元素為整個匹配字串,後續元素為各個子字串。程式碼範例:regexp.FindStringSubmatch(text,pattern)傳回符合子字串的切片。實戰案例:可用於匹配電子郵件地址中的域名,例如:email:="user@example.com",pattern:=@([^\s]+)$獲取域名match[1]。

Go框架開發常見問題:框架選擇:取決於應用需求和開發者偏好,如Gin(API)、Echo(可擴展)、Beego(ORM)、Iris(效能)。安裝和使用:使用gomod指令安裝,導入框架並使用。資料庫互動:使用ORM庫,如gorm,建立資料庫連線和操作。身份驗證和授權:使用會話管理和身份驗證中間件,如gin-contrib/sessions。實戰案例:使用Gin框架建立一個簡單的部落格API,提供POST、GET等功能。

Go語言中使用預先定義時區包含下列步驟:匯入"time"套件。透過LoadLocation函數載入特定時區。在建立Time物件、解析時間字串等操作中使用已載入的時區,進行日期和時間轉換。使用不同時區的日期進行比較,以說明預先定義時區功能的應用。
