ANi*_*sus 16 string pointers go string-literals
在我的应用程序中,我将经常传递对静态字符串的引用.我希望避免Go为每次调用分配内存,但是我没有将地址输入到我的字符串文字中.
为什么不能获取字符串文字的地址(参见test1()
下面的例子)?我是否误解了语法,或者由于Go的内部工作原因这是一个限制?
如果不可能,最好的解决方案是什么?
test2()
有效,但var hej
每次都会分配内存吗?
test3()
不会分配任何新的内存,但我希望避免功能之外的混乱.
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())
}
Run Code Online (Sandbox Code Playgroud)
感谢帮助!
Son*_*nia 13
对于传递"静态"字符串的情况的最佳解决方案的问题,
提供"不要担心分配字符串"的建议是很诱人的,因为在你描述传递相同字符串的位置时,这实际上是正确的,可能很多次.一般来说,考虑内存使用真的很好.这是非常糟糕的猜测,更糟糕的是根据另一种语言的经验猜测.
这是您的程序的修改版本.您认为内存分配在哪里?
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())
}
Run Code Online (Sandbox Code Playgroud)
现在问编译器:
> go tool 6g -S t.go
Run Code Online (Sandbox Code Playgroud)
(我将程序命名为t.go.)在输出中搜索对runtime.new的调用.只有一个!我会为你破坏它,它在test1中.
因此,如果没有太多的切线,那么对编译器输出的一点看就表明我们通过使用字符串类型而不是*string来避免分配.
jim*_*imt 10
获取文字的地址(字符串,数字等)是非法的,因为它具有模糊的语义.
你拿的是实际常数的地址吗?哪个允许修改值(并可能导致运行时错误)或者您是否要分配新对象,复制常量并将地址转换为新版本?
test2
由于您正在处理明确定义语义的现有变量,因此不存在这种歧义.如果将字符串定义为,则同样不起作用const
.
语言规范通过明确地不允许您要求的内容来避免这种模糊性.解决方案是test2
.虽然它稍微冗长一点,但它使规则简单而干净.
当然,每个规则都有其例外,而在Go中这涉及复合文字:以下是合法的,并在规范中定义如下:
func f() interface{} {
return &struct {
A int
B int
}{1, 2}
}
Run Code Online (Sandbox Code Playgroud)
go中的字符串是不可变的,只是一个指针和一个长度(总长度:2个字).
因此,您不必使用指针来有效地处理它.
只需传递字符串.
在 Go 中传递字符串通常不会分配内存 - 它是一种值类型(指向字节的 ptr 和 int len)。
仅支持复合文字,例如
v := &T{1, "foo"}
但不适用于像这样的简单值
w := &1
x := &"foo"