String 子字符串和Go垃圾收集器

String 子字符串和Go垃圾收集器,string,go,slice,idioms,String,Go,Slice,Idioms,在Go中获取字符串的子字符串时,不会分配新内存。相反,子字符串的底层表示包含一个数据指针,该数据指针是原始字符串的数据指针的偏移量 这意味着,如果我有一个大字符串,并且希望跟踪一个小的子字符串,垃圾收集器将无法释放任何大字符串,直到我释放对较短子字符串的所有引用 切片也有类似的问题,但可以通过使用copy()复制子切片来解决。我不知道有任何类似的字符串复制操作。制作子字符串“副本”的惯用且最快的方法是什么?例如 package main import ( "fmt" "unsa

在Go中获取字符串的子字符串时,不会分配新内存。相反,子字符串的底层表示包含一个数据指针,该数据指针是原始字符串的数据指针的偏移量

这意味着,如果我有一个大字符串,并且希望跟踪一个小的子字符串,垃圾收集器将无法释放任何大字符串,直到我释放对较短子字符串的所有引用

切片也有类似的问题,但可以通过使用copy()复制子切片来解决。我不知道有任何类似的字符串复制操作。制作子字符串“副本”的惯用且最快的方法是什么?

例如

package main

import (
    "fmt"
    "unsafe"
)

type String struct {
    str *byte
    len int
}

func main() {
    str := "abc"
    substr := string([]byte(str[1:]))
    fmt.Println(str, substr)
    fmt.Println(*(*String)(unsafe.Pointer(&str)), *(*String)(unsafe.Pointer(&substr)))
}
输出:

abc bc
{0x4c0640 3} {0xc21000c940 2}

我知道这是一个老问题,但有几种方法可以做到这一点,而无需创建所需数据的两个副本

首先是创建子字符串的
[]字节
,然后使用
不安全的指针
将其强制为
字符串
。这是因为
[]字节
的头与
字符串
的头相同,只是
[]字节
的末尾有一个额外的
Cap
字段,所以它只是被截断了

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    str := "foobar"
    byt := []byte(str[3:])
    sub := *(*string)(unsafe.Pointer(&byt))
    fmt.Println(str, sub)
}

第二种方法是使用
reflect.StringHeader
reflect.SliceHeader
进行更明确的头传输

package main

import (
    "fmt"
    "unsafe"
    "reflect"
)

func main() {
    str := "foobar"
    byt := []byte(str[3:])
    bytPtr := (*reflect.SliceHeader)(unsafe.Pointer(&byt)).Data
    strHdr := reflect.StringHeader{Data: bytPtr, Len: len(byt)}
    sub := *(*string)(unsafe.Pointer(&strHdr))
    fmt.Println(str, sub)
}

这个解决方案不会导致生成两个子字符串副本吗?一个用于转换为[]字节,另一个用于转换回字符串?是的,很遗憾。然而,字节片是临时的,这是Go的一个缺点。应该可以为此使用make(string,foo[x:y])。