for j:=0;j<4 ;j++ { } 与for _,v :=range persons {} 区别

请大神详细讲解一下这二者的区别(比较深入点比较好) ```go package main import ( "fmt" "strconv" ) func main() { person:=new(Person) persons:=make([]Person,4) for i:=0;i<4;i++{ person.Id= strconv.Itoa(i) person.Name = "sun" person.AvatarUrl="AAAAA" persons[i]=*person } fmt.Println("----原始数组-----") fmt.Println(persons) for _,v :=range persons { v.Name="SSS" } fmt.Println("----range-----") fmt.Println(persons) for j:=0;j<4 ;j++ { persons[j].Name="JJJ" } fmt.Println("----iiiii-----") fmt.Println(persons) } type Person struct { Id string Name string AvatarUrl string } ``` 输出结果为: ```go ----原始数组----- [{0 sun AAAAA} {1 sun AAAAA} {2 sun AAAAA} {3 sun AAAAA}] ----range----- [{0 sun AAAAA} {1 sun AAAAA} {2 sun AAAAA} {3 sun AAAAA}] ----iiiii----- [{0 JJJ AAAAA} {1 JJJ AAAAA} {2 JJJ AAAAA} {3 JJJ AAAAA}] ```
已邀请:

angelina - 初学者

赞同来自: astaxie niugou wangfei leoliu sheepbao raindylong Xanthus更多 »

```go
for _,v :=range persons {
v.Name="SSS"
}
```
是从切片persons 中复制对应的person元素并生成一个副本v,所以任何作用于v的修改都只会作用于这个复制出来的副本,并不会影响切片中的元素。
```go
for j:=0;j<4 ;j++ {
persons[j].Name="JJJ"
}
```
但是这种循环方式中的persons[j]是直接指向persons中的每个元素,所以能够修改其中的值。

sheepbao - https://sheepbao.github.io 爱go,爱编程,领域网络开发,流媒体、分布式、网络加速

赞同来自: qi19901212

```go
package main

import (
"fmt"
"strconv"
)

func main() {
person := new(Person)
persons := make([]*Person, 4)
for i := 0; i < 4; i++ {
person.Id = strconv.Itoa(i)
person.Name = "sun"
person.AvatarUrl = "AAAAA"
persons[i] = person
}
fmt.Println("----原始数组-----")
for _, p := range persons {
fmt.Printf("%#v\n", p)
}
for _, v := range persons {
v.Name = "SSS"
}
fmt.Println("----range-----")
for _, p := range persons {
fmt.Printf("%#v\n", p)
}
for j := 0; j < 4; j++ {
persons[j].Name = "JJJ"
}
fmt.Println("----iiiii-----")
for _, p := range persons {
fmt.Printf("%#v\n", p)
}
}

type Person struct {
Id string
Name string
AvatarUrl string
}
```
```
----原始数组-----
&main.Person{Id:"3", Name:"sun", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"sun", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"sun", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"sun", AvatarUrl:"AAAAA"}
----range-----
&main.Person{Id:"3", Name:"SSS", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"SSS", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"SSS", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"SSS", AvatarUrl:"AAAAA"}
----iiiii-----
&main.Person{Id:"3", Name:"JJJ", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"JJJ", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"JJJ", AvatarUrl:"AAAAA"}
&main.Person{Id:"3", Name:"JJJ", AvatarUrl:"AAAAA"}
```
要注意如果slice是指针的话,在range也可以更改原slice的

chai2010 - 数盲患者

性能可能会有一定的区别, 因为range遍历是可以确保索引范围不会溢出, 不需要做边界判断.
想简单回答这个问题只能告诉你语言的规则,推荐看 [《golang for语句完全指南》](https://sheepbao.github.io/post/golang_for_range_complete_guide/)

一下引用其中的一段介绍:

>for语句的内部实现-array
golang的for语句,对于不同的格式会被编译器编译成不同的形式,如果要弄明白需要看 golang的编译器和相关数据结构的源码, 数据结构源码还好,但是编译器是用C++写的,本人C++是个弱鸡,这里只讲array内部实现。

```go
// The loop we generate:
// len_temp := len(range)
// range_temp := range
// for index_temp = 0; index_temp < len_temp; index_temp++ {
// value_temp = range_temp[index_temp]
// index = index_temp
// value = value_temp
// original body
// }

// 例如代码:
array := [2]int{1,2}
for k,v := range array {
f(k,v)
}

// 会被编译成:
len_temp := len(array)
range_temp := array
for index_temp = 0; index_temp < len_temp; index_temp++ {
value_temp = range_temp[index_temp]
k = index_temp
v = value_temp
f(k,v)
}
```
> 所以像遍历一个数组,最后生成的代码很像C语言中的遍历,而且有两个临时变量index_temp,value_temp, 在整个遍历中一直复用这两个变量。所以会导致开头问题2的问题(详细解答会在后边)。

要回复问题请先登录注册