英文:
Is there any way to tell if two strings share memory in Go?
问题
在Go语言中,字符串在内部以C结构体的形式存储:
struct String // 这是C代码(不是Go代码)
{
byte* str;
int32 len;
};
假设我有以下变量:
a0 := "ap" // 这是Go代码
a1 := "ple"
b0 := "app"
b1 := "le"
a := a0 + a1
b := b0 + b1
c := "apple"
d := c
那么以下代码:
fmt.Println("a == b =", a == b, "&a == &b =", &a == &b)
fmt.Println("c == d =", c == d, "&c == &d =", &c == &d)
输出结果为:
a == b = true, &a == &b = false
c == d = true, &c == &d = false
因为&a == &b
比较的是C结构体的地址,而a == b
比较的是字符串的值。
是否有任何方法可以测试字符串本身是否存储在相同的位置(即C结构体的str
字段具有相同的值),以便比较a
和b
很可能返回false
,而比较c
和d
几乎肯定返回true
?
英文:
In Go, strings are stored internally as the C-struct:
struct String // This is C code (not Go)
{
byte* str;
int32 len;
};
Let's say I have the following variables:
a0 := "ap" // This is Go code
a1 := "ple"
b0 := "app"
b1 := "le"
a := a0 + a1
b := b0 + b1
c := "apple"
d := c
Then the following code:
fmt.Println("a == b = %t, &a == &b = %t", a == b, &a == &b)
fmt.Println("c == d = %t, &c == &d = %t", c == d, &c == &d)
outputs:
a == b = true, &a == &b = false
c == d = true, &c == &d = false
because &a == &b
compares the addresses of the C-structs, while a == b
compares the values of the strings.
Is there any way to test whether the strings themselves are stored in the same place (i.e. the str
field in the C-struct has the same value), such that comparing a
and b
would most likely yield false
, while comparing c
and d
would almost certainly yield true
?
答案1
得分: 5
是的,这是可能的。使用反射包并获取两个string
实例的String Headers。然后,您可以比较Data
和Len
字段来计算字符串后备数组是否在内存中重叠。
注意:StringHeader
结构体是实现细节,它没有在语言规范中提到。因此,任何执行上述讨论中的操作的代码实际上并不是可移植的Go代码。换句话说,我不鼓励在好奇心/研究等之外的情况下使用此类代码。根据文档:
StringHeader
是字符串的运行时表示。它不能安全或可移植地使用,并且其表示可能会在以后的版本中更改。此外,Data
字段不足以保证其引用的数据不会被垃圾回收,因此程序必须保持对底层数据的单独、正确类型的指针。
编辑:
未经测试的代码,从string
实例str
获取*reflect.StringHeader
hdr
:
hdr := (*reflect.StringHeader)(unsafe.Pointer(&str))
英文:
Yes, it's possible. Use the reflect package and obtain the String Headers of two string
instances. Then you can compare both the Data
and Len
fields to compute whether the string backing arrays do overlap in memory.
Note: The StringHeader
struct is an implementation detail, it's not mentioned by the language specs. Thus, any code doing things like discussed in the above paragraph is not really portable Go. IOW, I discourage to use such code outside of curiosity/research etc. From the docs:
> StringHeader is the runtime representation of a string. It cannot be used safely or portably and its representation may change in a later release. Moreover, the Data field is not sufficient to guarantee the data it references will not be garbage collected, so programs must keep a separate, correctly typed pointer to the underlying data.
EDIT:
Untested code to obtain a *reflect.StringHeader
hdr
from a string
instance str
:
hdr := (*reflect.StringHeader)(unsafe.Pointer(&str))
答案2
得分: -1
字符串的内部化程度是Go编译器的实现细节。对于当前的gc
和gccgo
编译器,相同的字符串字面量在编译和链接时被内部化。其他在运行时生成的字符串字面量和字符串不会被内部化。
英文:
The degree to which string
s are interned is a Go compiler implementation detail. For the current gc
and gccgo
compilers, identical string
literals are interned at compile and link time. Other string
literals and string
s generated at runtime are not interned.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论