Inhaltsverzeichnis
for i := 0; i < 10; i++ {}
Nach dem Login kopieren
3.for { " >1.für relationalen Ausdruck oder logischen Ausdruck; code>
for i := 0; i < 10; i++ {}
Nach dem Login kopieren
3.for {
range语句
for循环尤其是range语句,在平时开发过程中频繁使用,但很多开发者(本人算一个)经常会在以下场景中踩坑。
场景一,使用循环迭代器的变量" >场景一,使用循环迭代器的变量
场景二,在循环体内使用goroutines" >场景二,在循环体内使用goroutines
Heim Backend-Entwicklung Golang Notieren Sie die Fallstricke von Gos Schleifendurchquerung

Notieren Sie die Fallstricke von Gos Schleifendurchquerung

Feb 19, 2021 pm 05:38 PM
go golang

-Tutorialspalte mit der Schleife von GO geteilt, um die kleine Grube zu verwenden, ich hoffe, dass es den Freunden, die es brauchen, hilfreich sein wird!

Notieren Sie die Fallstricke von Gos SchleifendurchquerungIn der Prozesssteuerung von Golang gibt es zwei Arten von Schleifenanweisungen: for und range.

für Anweisung

n := 10for n > 0 {
 n--}
Nach dem Login kopieren

range-Anweisung1.for 赋值表达式; 关系表达式或逻辑表达式; 赋值表达式 { }

for {
 fmt.Println("hello world")
}
// 等价于
// for true {
//     fmt.Println("hello world")
// }
Nach dem Login kopieren

2.for 关系表达式或逻辑表达式 { }

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
Nach dem Login kopieren

3.for { }

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
Nach dem Login kopieren

range语句

Golang range类似迭代器操作,可以对 slice、map、数组、字符串等进行迭代循环。在字符串、数组和切片中它返回 (索引, 值) ,在集合中返回 (键, 值),但若当只有一个返回值时,第一个参数是索引或键。

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
Nach dem Login kopieren

for循环尤其是range语句,在平时开发过程中频繁使用,但很多开发者(本人算一个)经常会在以下场景中踩坑。

先来看一个明显的错误:

func main() {
    var out [][]int
    for _, i := range [][1]int{{1}, {2}, {3}} {
        out = append(out, i[:])
    }
    fmt.Println("Values:", out)}// 输出结果// [[3] [3] [3]]
Nach dem Login kopieren

分析

out是一个整型指针数组变量,在for循环中,声明了一个i变量,每次循环将i的地址追加到out切片中,但是每次追加的其实都是i变量,因此我们追加的是一个相同的地址,而该地址最终的值是3。

正确做法

解开代码中的注释// i := i,每次循环时都重新创建一个新的i变量。


再看一个比较隐秘的错误:

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
Nach dem Login kopieren

分析

大多数人就是在range这里给变量赋值的时候踩坑,因为比较隐秘,其实情况和上面的一样,range在遍历值类型时,其中的v是一个局部变量,只会声明初始化一次,之后每次循环时重新赋值覆盖前面的,所以给a2[i]赋值的时候其实都是同一个地址&v,而v最终的值为a1最后一个元素的值,也就是3。

正确做法

a2[i]赋值时传递原始指针,即a2[i] = &a1[i]
②创建临时变量t := va2[i] = &t
③闭包(与②原理一样),func(v int) { a2[i] = &v }(v)


更为隐秘的还有:

for _, val := range values {
    wg.Add(1)
    val := val    go func() {
        fmt.Println(val)
        wg.Done()
    }()}
Nach dem Login kopieren

原理也是一样的,不论遍历多少次,i[:]总是被本次遍历的值所覆盖

for _, val := range values {
    wg.Add(1)
    go func(val int) {
        fmt.Println(val)
        wg.Done()
    }(val)}
Nach dem Login kopieren

分析

对于主协程来讲,循环是很快就跑完的,而这个时候各个协程可能才开始跑,此时val的值已经遍历到最后一个了,所以各协程都输出了3。(如果遍历数据庞大,主协程遍历耗时较久的话,goroutine的输出会根据当时候的val

Der Golang-Bereich ähnelt einer Iteratoroperation und kann über Slices, Karten, Arrays, Strings usw. iterieren. Es gibt (Index, Wert) in Strings, Arrays und Slices und (Schlüssel, Wert) in Sammlungen zurück, aber wenn es nur einen Rückgabewert gibt, ist das erste Argument der Index oder Schlüssel.
rrreee

Die for-Schleife, insbesondere die Range-Anweisung, wird im täglichen Entwicklungsprozess häufig verwendet, aber viele Entwickler (einschließlich mir) machen in den folgenden Szenarien häufig Fehler.

Szenario 1, Verwendung der Variablen des Schleifeniterators

Sehen wir uns zunächst einen offensichtlichen Fehler an: 🎜rrreee🎜🎜Analyse🎜🎜🎜out ist eine ganzzahlige Zeiger-Array-Variable im for Schleife wird eine i-Variable deklariert, und jede Schleife hängt die Adresse von i an das out-Slice an, aber was jedes Mal angehängt wird, ist tatsächlich i-Variable, also hängen wir dieselbe Adresse an und der Endwert der Adresse ist 3. 🎜🎜🎜Richtiger Ansatz🎜🎜🎜Entsperren Sie den Kommentar // i := i im Code und erstellen Sie bei jedem Schleifendurchlauf eine neue i-Variable. 🎜
🎜Werfen wir einen Blick auf einen geheimnisvolleren Fehler: 🎜rrreee🎜🎜Analyse🎜🎜🎜Die meisten Leute machen Fehler, wenn sie den Variablen hier im Bereich Werte zuweisen, weil es relativ ist Tatsächlich ist die Situation dieselbe wie oben: Wenn range Werttypen durchläuft, ist v eine lokale Variable. Sie wird nur einmal deklariert und initialisiert und dann neu zugewiesen Jedes Mal, wenn eine Schleife ausgeführt wird, um die vorherige zu überschreiben, haben sie bei der Zuweisung von Werten zu a2[i] tatsächlich alle dieselbe Adresse &v und den Endwert von v ist a1Der Wert des letzten Elements, nämlich 3. 🎜🎜🎜Richtiger Ansatz🎜🎜🎜①a2[i] Übergeben Sie beim Zuweisen den ursprünglichen Zeiger, d. h. a2[i] = &a1[i]
②Erstellen Sie eine temporäre Variable t := v; a2[i] = &t
③ Abschluss (gleiches Prinzip wie ②), func(v int) { a2 [i] = &v }(v)🎜
🎜Das Geheimnisvollere ist: 🎜rrreee🎜Das Prinzip ist das gleiche, egal wie oft es durchlaufen wird, i[ :] Wird immer durch den Wert dieser Durchquerung überschrieben. Szenario 2: Verwendung von Goroutinen hat gerade mit der Ausführung begonnen. Zu diesem Zeitpunkt wurde der Wert von val auf den letzten Wert übertragen, sodass jede Coroutine 3 ausgibt. (Wenn die Durchlaufdaten sehr groß sind und der Durchlauf der Haupt-Coroutine lange dauert, basiert die Ausgabe der Goroutine auf dem Wert von val zu diesem Zeitpunkt, sodass das Ausgabeergebnis möglicherweise nicht dasselbe ist jedes Mal.) 🎜🎜🎜 Lösung🎜🎜🎜①Verwenden Sie temporäre Variablen🎜rrreee🎜②Verwenden Sie Verschlüsse🎜rrreee

Das obige ist der detaillierte Inhalt vonNotieren Sie die Fallstricke von Gos Schleifendurchquerung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat -Befehle und wie man sie benutzt
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Wie kann ich Dateien mit Golang sicher lesen und schreiben? Wie kann ich Dateien mit Golang sicher lesen und schreiben? Jun 06, 2024 pm 05:14 PM

Das sichere Lesen und Schreiben von Dateien in Go ist von entscheidender Bedeutung. Zu den Richtlinien gehören: Überprüfen von Dateiberechtigungen, Schließen von Dateien mithilfe von Verzögerungen, Validieren von Dateipfaden, Verwenden von Kontext-Timeouts. Das Befolgen dieser Richtlinien gewährleistet die Sicherheit Ihrer Daten und die Robustheit Ihrer Anwendungen.

Wie konfiguriere ich den Verbindungspool für die Golang-Datenbankverbindung? Wie konfiguriere ich den Verbindungspool für die Golang-Datenbankverbindung? Jun 06, 2024 am 11:21 AM

Wie konfiguriere ich Verbindungspooling für Go-Datenbankverbindungen? Verwenden Sie den DB-Typ im Datenbank-/SQL-Paket, um eine Datenbankverbindung zu erstellen. Legen Sie MaxOpenConns fest, um die maximale Anzahl gleichzeitiger Verbindungen festzulegen. Legen Sie ConnMaxLifetime fest, um den maximalen Lebenszyklus der Verbindung festzulegen.

Wie verwende ich Gomega für Behauptungen in Golang-Unit-Tests? Wie verwende ich Gomega für Behauptungen in Golang-Unit-Tests? Jun 05, 2024 pm 10:48 PM

So verwenden Sie Gomega für Behauptungen beim Golang-Unit-Testing. Beim Golang-Unit-Testing ist Gomega eine beliebte und leistungsstarke Assertionsbibliothek, die umfangreiche Assertionsmethoden bereitstellt, damit Entwickler Testergebnisse einfach überprüfen können. Installieren Sie Gomegagoget-ugithub.com/onsi/gomega. Verwenden Sie Gomega für Behauptungen. Hier sind einige häufige Beispiele für die Verwendung von Gomega für Behauptungen: 1. Import von Gleichheitszusicherungen „github.com/onsi/gomega“ funcTest_MyFunction(t*testing.T){

Golang Framework vs. Go Framework: Vergleich der internen Architektur und externen Funktionen Golang Framework vs. Go Framework: Vergleich der internen Architektur und externen Funktionen Jun 06, 2024 pm 12:37 PM

Der Unterschied zwischen dem GoLang-Framework und dem Go-Framework spiegelt sich in der internen Architektur und den externen Funktionen wider. Das GoLang-Framework basiert auf der Go-Standardbibliothek und erweitert deren Funktionalität, während das Go-Framework aus unabhängigen Bibliotheken besteht, um bestimmte Zwecke zu erreichen. Das GoLang-Framework ist flexibler und das Go-Framework ist einfacher zu verwenden. Das GoLang-Framework hat einen leichten Leistungsvorteil und das Go-Framework ist skalierbarer. Fall: Gin-Gonic (Go-Framework) wird zum Erstellen der REST-API verwendet, während Echo (GoLang-Framework) zum Erstellen von Webanwendungen verwendet wird.

Wie speichere ich JSON-Daten in einer Datenbank in Golang? Wie speichere ich JSON-Daten in einer Datenbank in Golang? Jun 06, 2024 am 11:24 AM

JSON-Daten können mithilfe der gjson-Bibliothek oder der json.Unmarshal-Funktion in einer MySQL-Datenbank gespeichert werden. Die gjson-Bibliothek bietet praktische Methoden zum Parsen von JSON-Feldern, und die Funktion json.Unmarshal erfordert einen Zieltypzeiger zum Unmarshalieren von JSON-Daten. Bei beiden Methoden müssen SQL-Anweisungen vorbereitet und Einfügevorgänge ausgeführt werden, um die Daten in der Datenbank beizubehalten.

Was sind die Best Practices für die Fehlerbehandlung im Golang-Framework? Was sind die Best Practices für die Fehlerbehandlung im Golang-Framework? Jun 05, 2024 pm 10:39 PM

Best Practices: Erstellen Sie benutzerdefinierte Fehler mit klar definierten Fehlertypen (Fehlerpaket). Stellen Sie weitere Details bereit. Protokollieren Sie Fehler ordnungsgemäß. Geben Sie Fehler korrekt weiter und vermeiden Sie das Ausblenden oder Unterdrücken. Wrappen Sie Fehler nach Bedarf, um Kontext hinzuzufügen

Wie finde ich den ersten Teilstring, der mit einem regulären Golang-Ausdruck übereinstimmt? Wie finde ich den ersten Teilstring, der mit einem regulären Golang-Ausdruck übereinstimmt? Jun 06, 2024 am 10:51 AM

Die FindStringSubmatch-Funktion findet die erste Teilzeichenfolge, die mit einem regulären Ausdruck übereinstimmt: Die Funktion gibt ein Segment zurück, das die passende Teilzeichenfolge enthält, wobei das erste Element die gesamte übereinstimmende Zeichenfolge und die nachfolgenden Elemente einzelne Teilzeichenfolgen sind. Codebeispiel: regexp.FindStringSubmatch(text,pattern) gibt einen Ausschnitt übereinstimmender Teilzeichenfolgen zurück. Praktischer Fall: Es kann verwendet werden, um den Domänennamen in der E-Mail-Adresse abzugleichen, zum Beispiel: email:="user@example.com", pattern:=@([^\s]+)$, um die Übereinstimmung des Domänennamens zu erhalten [1].

Ist es vielversprechender, Java oder Golang von Front-End zu Back-End-Entwicklung zu verwandeln? Ist es vielversprechender, Java oder Golang von Front-End zu Back-End-Entwicklung zu verwandeln? Apr 02, 2025 am 09:12 AM

Backend Learning Path: Die Erkundungsreise von Front-End zu Back-End als Back-End-Anfänger, der sich von der Front-End-Entwicklung verwandelt, Sie haben bereits die Grundlage von Nodejs, ...

See all articles