常量如何在Go中起作用?

时间:2016-07-13 23:17:41

标签: go

在Go中,哪个片段分配的对象较少?或者他们都使用相同数量的分配,如果是这样的话;为什么? (:

for i := 0; i < 10000000; i++ {
        log.println("hello")
    }

以下代码是否仅分配1个字符串?

const (
    HELLO string = "hello"
)

for i := 0; i < 10000000; i++ {
    log.println(HELLO)
}

2 个答案:

答案 0 :(得分:5)

这是一个改编你的程序,在两种情况下打印出基础字符串表示。

package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

const (
    Hello string = "hello"
)

func main() {
    for i := 0; i < 3; i++ {
        a := "hello"
        sh := (*reflect.StringHeader)(unsafe.Pointer(&a))
        fmt.Println(a, " ", *sh)
    }

    fmt.Println()

    for i := 0; i < 3; i++ {
        a := Hello
        sh := (*reflect.StringHeader)(unsafe.Pointer(&a))
        fmt.Println(a, " ", *sh)
    }
}

这是输出:

hello   {4870353 5}
hello   {4870353 5}
hello   {4870353 5}

hello   {4870353 5}
hello   {4870353 5}
hello   {4870353 5}

输出中{}中的字符串标题显示指向字符数据的指针(&#34; hello&#34;),以及字符串的长度。

你可以看到整个程序中指向字符串数据的指针是相同的:字节数据&#34;你好&#34;无论循环计数是什么,无论它是硬编码字符串还是常量,都只引用一个内存地址(此处为4870353)。

语言规范本身并不保证这种行为,但是常量字符串实习是一种自然的优化,如果以任何明显不同的方式表现,那将是令人惊讶的。

答案 1 :(得分:1)

查找Go是否进行某些分配的最简单方法是编写基准。在您的情况下,代码可能如下所示:

package sof

import "log"

const (
    HELLO = "hello"
)

func forString(max int) {
    for i := 0; i < max; i++ {
        logMsg("hello", false)
    }
}

func forConst(max int) {
    for i := 0; i < max; i++ {
        logMsg(HELLO, false)
    }
}

func logMsg(msg string, stdOut bool) {
    if stdOut {
        log.Println(msg)
    }
}

基准:

package sof

import "testing"

func BenchmarkForString(b *testing.B) {
    for i := 0; i < b.N; i++ {
        forString(i)
    }
}

func BenchmarkForConst(b *testing.B) {
    for i := 0; i < b.N; i++ {
        forConst(i)
    }
}

然后你可以运行基准测试:

go test -bench=. -benchmem

非常重要的是-benchmem标志。如果没有它,您的基准测试只会告诉您基准时间 - 您不会获得有关每次操作的分配数量和平均分配大小的信息。

基准的输出:

testing: warning: no tests to run
BenchmarkForString-4      100000        133551 ns/op           0 B/op          0 allocs/op
BenchmarkForConst-4       100000        128585 ns/op           0 B/op          0 allocs/op
PASS
ok      .../sof 26.475s

在最后2列中,您可以获得有关分配大小及其编号的信息。在您的示例中,只有零,这意味着两个func都不进行任何分配:)