Link to String Literals in Go

In my application, I often pass references to a static string. I want Go not to allocate memory for each call, but I was not able to get the address into a string literal.

Why is it impossible to take the address of a string literal (see test1() in the example below)? Am I misunderstood the syntax, or is this limitation due to Go's internal actions?

If this is not possible, then what would be the best solution?

test2() works, but will it allocate memory for var hej every time?
test3() will not allocate new memory, but I want to avoid clutter outside the function.

 package main import "fmt" var konnichiwa = `こんにちは世界` // Gives the compile error `cannot take the address of "Hello world"` func test1() (*string) { return &`Hello world` } // Works fine func test2() (*string) { hej := `Hej världen` return &hej } func test3() (*string) { return &konnichiwa } func main(){ fmt.Println(*test1()) fmt.Println(*test2()) fmt.Println(*test3()) } 

Thanks for the help!

+6
source share
4 answers

Taking the address of a literal (string, number, etc.) is illegal because it has ambiguous semantics.

Do you take the address of the actual constant? What will allow you to change the value (and may lead to a runtime error), or do you want to select a new object, copy a constant and get the address in a new version?

This ambiguity does not exist in the case of test2 , since you are dealing with an existing variable from which semantics are clearly defined. The same will not work if the string was defined as const .

The language specification avoids this ambiguity by clearly not allowing what you are asking for. Solution test2 . Although it is somewhat more detailed, it keeps the rules simple and clean.

Of course, each rule has its own exceptions, and in Go this applies to composite literals: the following is legal and defined as such in the specification:

 func f() interface{} { return &struct { A int B int }{1, 2} } 
+5
source

The line in go is immutable and is just a pointer and a length (total length: 2 words).

This way you do not need to use a pointer to handle it efficiently.

Just pass the string.

+6
source

For the question of the best solution for your situation, walking around “static” lines

  • Pass a string type instead of * string.
  • Do not make assumptions about what is going on behind the scenes.

It is tempting to give advice “don't worry about the distribution of strings”, because this is really the case when you describe where the same string is transmitted, possibly many times. Although it's generally good to think about memory usage. It is simply very difficult to guess, and even worse to guess, based on experience with another language.

Here is a modified version of your program. Where do you assume memory is allocated?

 package main import "fmt" var konnichiwa = `こんにちは世界` func test1() *string { s := `Hello world` return &s } func test2() string { return `Hej världen` } func test3() string { return konnichiwa } func main() { fmt.Println(*test1()) fmt.Println(test2()) fmt.Println(test3()) } 

Now ask the compiler:

 > go tool 6g -S t.go 

(I called the program t.go.). Outputting results for calls to runtime.new. There is only one! I spoil it for you, this is in test1.

Therefore, without stopping at too much touch, a small look at the compiler’s output indicates that we avoid selection by working with a string type and not with a * string.

+5
source
  • Passing a line usually does not allocate memory in Go - it is a value type (ptr for bytes and int len).

  • Literal address capture is only supported for compound literals of type

    v := &T{1, "foo"}

    but not for simple meanings such as

    w := &1

    x := &"foo"

+2
source

Source: https://habr.com/ru/post/918393/


All Articles