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
Analyse
est une variable de tableau de pointeurs entiers. Dans la boucle for, une variable out
est déclarée. Chaque boucle ajoute l'adresse de i
à la tranche i
, mais chaque fois qu'elle est ajoutée, elle est en réalité ajoutée. out
variables, donc ce que nous ajoutons est la même adresse, et la valeur finale de l'adresse est 3. i
Approche correcteDébloquez les commentaires
dans le code et recréez une nouvelle // i := i
variable à chaque fois dans la boucle. 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
AnalyseLa plupart des gens attribuent des valeurs aux variables ici
Parfois Je marche sur le piège car il est relativement secret. En fait, la situation est la même que ci-dessus Lorsque range
traverse le type valeur, le range
est une variable locale. Elle ne sera déclarée et initialisée qu'une seule fois. puis réaffecté à chaque fois qu'il boucle pour écraser le précédent, donc lors de l'attribution de valeurs à v
, elles ont en fait toutes la même adresse a2[i]
, et la valeur finale de &v
est la valeur de la dernière. élément de v
, qui vaut 3. a1
Approche correcte①
Passez le pointeur d'origine lors de l'affectation, c'est-à-dire a2[i]
a2[i] = &a1[i]
② Créez une variable temporaire
; 🎜>t := v
③ Fermeture (identique au principe ②), 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]]
Le principe est le même, peu importe le nombre de fois qu'il est parcouru ,
Toujours écrasé par la valeur de ce parcoursi[:]
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
a été parcourue jusqu'à la dernière, donc chaque coroutine a une sortie <🎜. >. (Si les données de parcours sont énormes et que le parcours de la coroutine principale prend beaucoup de temps, la sortie de la goroutine sera basée sur la valeur dePour la coroutine principale, la boucle se termine rapidement et chaque coroutine ne peut commencer à s'exécuter qu'à ce moment-là, la valeur de
à ce moment-là, donc le résultat de sortie n'est pas nécessairement le même à chaque fois.) val
3
val
Solution
②Utiliser la fermeture①Utiliser une variable temporaire
for _, val := range values { wg.Add(1) val := val go func() { fmt.Println(val) wg.Done() }()}Copier après la connexion
for _, val := range values { wg.Add(1) go func(val int) { fmt.Println(val) wg.Done() }(val)}
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!