len()运行了多少次?

huangapple go评论74阅读模式
英文:

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(&quot;# b: len(list) %d\n&quot;, len(list))
    for i := 0; i &lt; len(list); i++ {
        fmt.Printf(&quot;# %d: len(list) %d, list[%d] == %d\n&quot;, i, len(list), i, list[i])
        if i == 2 {
            list = append(list, 4)
        }
    }
    fmt.Printf(&quot;# a: len(list) %d\n&quot;, 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).

huangapple
  • 本文由 发表于 2013年2月2日 21:38:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/14662438.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定