前言
for i:通过下标迭代。
for range:通过值拷贝迭代。
本文主要说明通过 for i 和 for range 迭代数据结构的性能差异。
注意:以下 1 和 2 两种迭代都是通过下标迭代,3 或 4 才是通过值拷贝迭代。
// 1for i := 0; i < len(nums); i++ {...}// 2for i := range nums// 3for _, num := range nums// 4for i, num := range nums
差异
一、for i 迭代能够修改数据,而 for range 迭代不能。
举个例子证明:
type Person struct {Name stringage int}func main() {students := []Person{{Name: "zwjason", age: 21},{Name: "bakanrian", age: 22},}// for range 尝试修改for _, student := range students {student.age = 20}for _, student := range students {fmt.Printf("%s %d\n", student.Name, student.age)}// for i 尝试修改for i := range students {students[i].age = 20}for _, student := range students {fmt.Printf("%s %d\n", student.Name, student.age)}}输出如下:zwjason 21bakanrian 22 // 修改失败zwjason 20bakanrian 20 // 修改成功
可以看到通过 for range 迭代修改失败,因为它是值拷贝迭代,student 只是复制了对应的值。
而 for i 迭代修改成功,因为它是直接对原数组操作。
二、当迭代的值占内存较大时,for range 的性能急剧下降。
比如当时用 for range 迭代如下数据结构:
type Person struct {Name stringscores [4096]int}
忽略 Name,一个 Person 实例占用内存至少为 84096 = 32 KB 。
原因是每次迭代都要拷贝至少 32 KB 的数据。
使用指针类型 []Person 可以避免这个问题,因为复制一个指针的代价一般只有 64 B (在 64 位机器)。
