有没有办法在Go中判断两个字符串是否共享内存?

huangapple go评论76阅读模式
英文:

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字段具有相同的值),以便比较ab很可能返回false,而比较cd几乎肯定返回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。然后,您可以比较DataLen字段来计算字符串后备数组是否在内存中重叠。

注意: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编译器的实现细节。对于当前的gcgccgo编译器,相同的字符串字面量在编译和链接时被内部化。其他在运行时生成的字符串字面量和字符串不会被内部化。

英文:

The degree to which strings 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 strings generated at runtime are not interned.

huangapple
  • 本文由 发表于 2013年7月27日 02:13:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/17888223.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定