stringgoequality

Is there any way to tell if two strings share memory in Go?


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?


Solution

  • 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))