常量在Go中如何工作?

In Go which snippet allocates less objects? Or do they both use the same amount of allocations, if so; why? (:

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

Does the code below allocates only 1 string?

const (
    HELLO string = "hello"
)

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

Here's an adaptation of your program that prints out the underlying string representation in both cases.

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)
    }
}

Here's the output:

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

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

The string header in {} in the output shows a pointer to the character data ("hello"), and the length of the string.

You can see that the pointer to the string data is the same throughout the program: the bytes data "hello" is referenced at exactly one memory address (here 4870353), no matter the loop count, and no matter whether it's a hardcoded string or a constant.

The language spec itself makes no guarantees about such behavior, but constant string interning is such a natural optimisation that it would be surprising if go behaved in any significantly different way.

The easiest way to find whether Go makes some allocations or not is writing the benchmark. In your case code might look like:

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)
    }
}

And benchmark:

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)
    }
}

Then you can just run the benchmark:

go test -bench=. -benchmem

Very important is -benchmem flag. Without it your benchmark tells you only about the benchmark time - you don't get info about number of allocations and average size of allocation per operation.

Output of the benchmark:

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

In last 2 columns you have an information about the size of allocations and its number. In your example there are only zeros which means that both funcs don't make any allocations : )