英文:
How many times len() runs?
问题
len(p)会运行多少次?只运行一次并保存结果,还是每次迭代都会运行?
func main() {
p := []int{2, 3, 5, 7, 11, 13}
for i:=0;i<len(p);i++ {}
}
英文:
How many times will len(p) run? Only one and the result will be saved, or will it run for each iteration?
func main() {
p := []int{2, 3, 5, 7, 11, 13}
for i:=0;i<len(p);i++ {}
}
答案1
得分: 12
len()
在切片上的使用被编译器优化了,就像访问一个局部变量一样。它实际上并不是一个函数调用。
你可以通过以下方式进行验证:
$ cat x.go package main import "fmt" func main() { a := []int{1,2, 3} fmt.Println(len(a)) }
然后查看编译器的输出:
$ go tool 6g -S x.go
--- prog list "main" --- 0000 (x.go:3) TEXT main+0(SB),$128-0 0001 (x.go:4) MOVQ $0,autotmp_0002+-80(SP) 0002 (x.go:4) MOVQ $0,autotmp_0002+-72(SP) 0003 (x.go:4) MOVQ $0,autotmp_0002+-64(SP) 0004 (x.go:4) LEAQ autotmp_0002+-80(SP),BX 0005 (x.go:4) MOVQ BX,autotmp_0001+-56(SP) 0006 (x.go:4) MOVQ autotmp_0001+-56(SP),BX 0007 (x.go:4) MOVQ statictmp_0000+0(SB),BP 0008 (x.go:4) MOVQ BP,(BX) 0009 (x.go:4) MOVQ statictmp_0000+8(SB),BP 0010 (x.go:4) MOVQ BP,8(BX) 0011 (x.go:4) MOVQ statictmp_0000+16(SB),BP 0012 (x.go:4) MOVQ BP,16(BX) 0013 (x.go:4) MOVQ autotmp_0001+-56(SP),BX 0014 (x.go:4) MOVQ $3,CX 0015 (x.go:5) LEAQ autotmp_0005+-16(SP),DI 0016 (x.go:5) MOVQ $0,AX 0017 (x.go:5) STOSQ , 0018 (x.go:5) STOSQ , 0019 (x.go:5) LEAQ autotmp_0005+-16(SP),BX 0020 (x.go:5) MOVQ BX,autotmp_0004+-48(SP) 0021 (x.go:5) MOVQ autotmp_0004+-48(SP),BX 0022 (x.go:5) MOVQ $1,SI 0023 (x.go:5) MOVQ $1,DX 0024 (x.go:5) MOVQ BX,autotmp_0003+-40(SP) 0025 (x.go:5) MOVQ autotmp_0003+-40(SP),BX 0026 (x.go:5) MOVQ $type.int+0(SB),AX 0027 (x.go:5) MOVQ AX,(BX) 0028 (x.go:5) MOVQ CX,8(BX) 0029 (x.go:5) MOVQ autotmp_0003+-40(SP),BX 0030 (x.go:5) MOVQ BX,(SP) 0031 (x.go:5) MOVQ SI,8(SP) 0032 (x.go:5) MOVQ DX,16(SP) 0033 (x.go:5) CALL ,fmt.Println+0(SB) 0034 (x.go:6) RET ,
注意到对fmt.Println
的调用,但没有对len
的调用。
英文:
<code>len()</code> on a slice is optimized by the compiler, it's like accessing a local variable. It's not really a function call.
You can verify with:
<pre>
$ cat x.go
package main
import "fmt"
func main() {
a := []int{1,2, 3}
fmt.Println(len(a))
}
</pre>
And then look at the compiler output:
$ go tool 6g -S x.go
<pre>
--- prog list "main" ---
0000 (x.go:3) TEXT main+0(SB),$128-0
0001 (x.go:4) MOVQ $0,autotmp_0002+-80(SP)
0002 (x.go:4) MOVQ $0,autotmp_0002+-72(SP)
0003 (x.go:4) MOVQ $0,autotmp_0002+-64(SP)
0004 (x.go:4) LEAQ autotmp_0002+-80(SP),BX
0005 (x.go:4) MOVQ BX,autotmp_0001+-56(SP)
0006 (x.go:4) MOVQ autotmp_0001+-56(SP),BX
0007 (x.go:4) MOVQ statictmp_0000+0(SB),BP
0008 (x.go:4) MOVQ BP,(BX)
0009 (x.go:4) MOVQ statictmp_0000+8(SB),BP
0010 (x.go:4) MOVQ BP,8(BX)
0011 (x.go:4) MOVQ statictmp_0000+16(SB),BP
0012 (x.go:4) MOVQ BP,16(BX)
0013 (x.go:4) MOVQ autotmp_0001+-56(SP),BX
0014 (x.go:4) MOVQ $3,CX
0015 (x.go:5) LEAQ autotmp_0005+-16(SP),DI
0016 (x.go:5) MOVQ $0,AX
0017 (x.go:5) STOSQ ,
0018 (x.go:5) STOSQ ,
0019 (x.go:5) LEAQ autotmp_0005+-16(SP),BX
0020 (x.go:5) MOVQ BX,autotmp_0004+-48(SP)
0021 (x.go:5) MOVQ autotmp_0004+-48(SP),BX
0022 (x.go:5) MOVQ $1,SI
0023 (x.go:5) MOVQ $1,DX
0024 (x.go:5) MOVQ BX,autotmp_0003+-40(SP)
0025 (x.go:5) MOVQ autotmp_0003+-40(SP),BX
0026 (x.go:5) MOVQ $type.int+0(SB),AX
0027 (x.go:5) MOVQ AX,(BX)
0028 (x.go:5) MOVQ CX,8(BX)
0029 (x.go:5) MOVQ autotmp_0003+-40(SP),BX
0030 (x.go:5) MOVQ BX,(SP)
0031 (x.go:5) MOVQ SI,8(SP)
0032 (x.go:5) MOVQ DX,16(SP)
0033 (x.go:5) CALL ,fmt.Println+0(SB)
0034 (x.go:6) RET ,
</pre>
Notice the CALL to <code>fmt.Println</code>, but no call to <code>len</code>.
答案2
得分: 9
尝试一个实验!http://play.golang.org/p/Eksb6bQovC
或者阅读文档:http://golang.org/ref/spec#For_statements(简而言之:“在每次迭代之前评估条件。”)
在你的例子中,len是条件的一部分,因此在每次迭代之前都会进行评估。条件评估为true的情况下会有六次迭代,然后再进行一次评估,此时条件为false,for循环退出。所以总共有七次迭代。
英文:
Try an experiment! http://play.golang.org/p/Eksb6bQovC
Or read the docs: http://golang.org/ref/spec#For_statements (TL;DR: "The condition is evaluated before each iteration.")
In your example, len is part of the condition so it is evaluated before each iteration. There will be an iteration for the six times the condition evaluates to true, then one more evaluation where it evaluates to false and the for loop exits. So, seven times in all.
答案3
得分: 2
第二个实验:
func Test_X(t *testing.T) {
list := []int{1, 2, 3}
fmt.Printf("# b: len(list) %d\n", len(list))
for i := 0; i < len(list); i++ {
fmt.Printf("# %d: len(list) %d, list[%d] == %d\n", i, len(list), i, list[i])
if i == 2 {
list = append(list, 4)
}
}
fmt.Printf("# a: len(list) %d\n", len(list))
}
输出:
=== RUN Test_X
# b: len(list) 3
# 0: len(list) 3, list[0] == 1
# 1: len(list) 3, list[1] == 2
# 2: len(list) 3, list[2] == 3
# 3: len(list) 4, list[3] == 4
# a: len(list) 4
--- PASS: Test_X (0.05 seconds)
这个实验说明了为什么不会优化掉len()调用。
英文:
A second experiment:
func Test_X(t * testing.T) {
list := []int{1, 2, 3}
fmt.Printf("# b: len(list) %d\n", len(list))
for i := 0; i < len(list); i++ {
fmt.Printf("# %d: len(list) %d, list[%d] == %d\n", i, len(list), i, list[i])
if i == 2 {
list = append(list, 4)
}
}
fmt.Printf("# a: len(list) %d\n", len(list))
}
output:
=== RUN Test_X
# b: len(list) 3
# 0: len(list) 3, list[0] == 1
# 1: len(list) 3, list[1] == 2
# 2: len(list) 3, list[2] == 3
# 3: len(list) 4, list[3] == 4
# a: len(list) 4
--- PASS: Test_X (0.05 seconds)
It gives a reason for not optimizing away then len() calls.
答案4
得分: -4
从算法的角度来看,条件在每一次循环步骤中都会被评估。在这种情况下,它似乎是对len(p)进行六次评估。
英文:
From the algorithmic point of view condition is evaluated for each step of the loop for. In this case it seems to be six times of the evaluation of the len(p).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论