Pointers 临时进入者的地址?
处理此类案件最干净的方法是什么:Pointers 临时进入者的地址?,pointers,return,go,temporary,rvalue,Pointers,Return,Go,Temporary,Rvalue,处理此类案件最干净的方法是什么: func a() string { /* doesn't matter */ } b *string = &a() 这将生成错误: 无法获取()的地址 我的理解是,如果取局部变量的地址,Go会自动将其提升到堆中。这里很清楚,返回值的地址将被获取。处理这个问题的惯用方法是什么?a()不指向堆栈上的变量。你不能指向堆栈(为什么?) 如果你愿意,你可以这样做 va := a() b := &va 但是您真正想要实现的目标有些不清楚。地址运
func a() string {
/* doesn't matter */
}
b *string = &a()
这将生成错误:
无法获取()的地址
我的理解是,如果取局部变量的地址,Go会自动将其提升到堆中。这里很清楚,返回值的地址将被获取。处理这个问题的惯用方法是什么?a()
不指向堆栈上的变量。你不能指向堆栈(为什么?)
如果你愿意,你可以这样做
va := a()
b := &va
但是您真正想要实现的目标有些不清楚。地址运算符返回一个指针,指向具有“home”的对象,例如变量。代码中表达式的值为“无家可归”。如果您确实需要*字符串,则必须分两步完成:
tmp := a(); b := &tmp
请注意,虽然*string有完全有效的用例,但很多时候使用它们是错误的。在Go
string
中,string是一种值类型,但传递起来很便宜(指针和int)。字符串的值是不可变的,更改*字符串
会更改“home”指向的位置,而不是字符串值,因此在大多数情况下根本不需要*字符串。请参阅<代码>&
只能用于:
如果创建指针的目的是创建具有动态生存期的对象,类似于
new()
或采用复合文字的地址,然后,您可以将函数调用的结果分配给一个变量,并获取该变量的地址。最后,您建议Go应允许您获取任何表达式的地址,例如:
i,j := 1,2
var p *int = &(i+j)
println(*p)
当前Go编译器打印错误:无法获取i+j的地址
在我看来,允许程序员获取任何表达式的地址:
- 似乎不是很有用(也就是说:在实际的围棋程序中,它似乎发生的概率很小)
- 这将使编译器和语言规范复杂化
将编译器和规范复杂化而没有什么好处似乎会适得其反。我最近为类似的事情纠缠不清 在您的示例中,首先讨论字符串是一种分散注意力的方法,请改用struct,将其重新写入如下内容:
func a() MyStruct {
/* doesn't matter */
}
var b *MyStruct = &a()
这将无法编译,因为无法获取()的地址。这样做:
func a() MyStruct {
/* doesn't matter */
}
tmpA := a()
var b *MyStruct = &tmpA
这将进行编译,但是您已经在堆栈上返回了MyStruct,在堆上分配了足够的空间来存储MyStruct,然后将内容从堆栈复制到堆中。如果要避免这种情况,请这样写:
func a2() *MyStruct {
/* doesn't matter as long as MyStruct is created on the heap (e.g. use 'new') */
}
var a *MyStruct = a2()
复制通常很便宜,但那些结构可能很大。更糟糕的是,当您想要修改结构并使其“粘贴”时,您不能复制然后修改副本
无论如何,当您使用返回类型的接口{}时,它会变得更加有趣。接口{}可以是结构或指向结构的指针。同样的复制问题也出现了。我想你需要更有效的Cpp的帮助 温度对象和右值
structType
对象,该对象将是不可寻址的临时结构对象。在这种情况下,Go中的地址不能引用字符串文字
最后但并非最不重要的一个例外是,在go中,您可以获取复合文本的地址。天哪,真是一团糟。在分配给新变量时,您无法直接获得结果的引用,但您有一种惯用的方法,只需预先声明“b”指针即可实现这一点,而无需使用临时变量(这是无用的)-这是您错过的真正步骤:
func a()字符串{
return“没关系”
}
b:=new(string)//b是指向空白字符串(“归零”值)的指针
*b=a()//b现在是指向`a()结果的指针`
*b
用于取消指针引用并直接访问存储数据的内存区域(当然是在堆上)
玩一下代码:在写这篇文章时,没有一个答案能真正解释为什么会出现这种情况 考虑以下几点:
func main() {
m := map[int]int{}
val := 1
m[0] = val
v := &m[0] // won't compile, but let's assume it does
delete(m, 0)
fmt.Println(v)
}
如果这个代码片段真的被编译了,那么v
会指向什么呢!?它是一个悬空指针,因为基础对象已被删除
有鉴于此,不允许寻址临时变量或从
a()返回*字符串似乎是一个合理的限制。您还可以获取复合文本的地址,它不需要“主”复合文本