片段是否执行基础数据的复制?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了片段是否执行基础数据的复制?相关的知识,希望对你有一定的参考价值。

我正在尝试使用string库从utf-8 utf8有效地计算符文。此示例是否最佳,因为它不复制基础数据? https://golang.org/pkg/unicode/utf8/#example_DecodeRuneInString

func main() {
    str := "Hello, 世界" // let's assume a runtime-provided string
    for len(str) > 0 {
        r, size := utf8.DecodeRuneInString(str)
        fmt.Printf("%c %v
", r, size)
        str = str[size:] // performs copy?
    }
}

我在(不安全)反射库中找到了StringHeader。这是Go中string的确切结构吗?如果是这样,可以想象切片只是更新Data或完全分配一个新的StringHeader

type StringHeader struct {
        Data uintptr
        Len  int
}

额外奖励:我在哪里可以找到执行string切片的代码,以便我可以自己查找?这些都是? https://golang.org/src/runtime/slice.go https://golang.org/src/runtime/string.go

这个related SO answer表明运行时字符串在从string转换为[]byte时会产生副本。

答案

Slicing Strings

片段切片执行底层数据的复制吗?

不,不是的。请参阅Russ Cox的这篇文章:

字符串在内存中表示为包含指向字符串数据和长度的指针的2字结构。因为字符串是不可变的,所以多个字符串共享相同的存储是安全的,因此切片会产生一个新的双字结构,其中可能有不同的指针和长度仍然指向相同的字节序列。这意味着可以在不分配或复制的情况下完成切片,从而使字符串切片与传递显式索引一样高效。

- Go Data Structures

Slices, Performance, and Iterating Over Runes

切片基本上是三件事:长度,容量和指向底层数组中某个位置的指针。

因此,切片本身不是很大:int和指针(实现细节中可能还有其他一些小东西)。因此,制作切片副本所需的分配非常小,并且不依赖于底层数组的大小。当您只是更新长度,容量和指针位置时,不需要新的分配,例如在第2行:

foo := []int{3, 4, 5, 6}
foo = foo[1:]

相反,它必须分配一个新的底层数组,以便感受到性能影响。

Go中的字符串是不可变的。因此,要更改字符串,您需要创建一个新字符串。但是,字符串与字节切片密切相关,例如,你可以用字符串创建一个字节切片

foo := `here's my string`
fooBytes := []byte(foo)

我相信会分配一个新的字节数组,因为:

一个字符串实际上是一个只读的字节片

根据Go Blog(见Strings, bytes, runes and characters in Go)。通常,您可以使用切片来更改基础数组的内容,因此要从字符串生成可用的字节切片,您必须制作副本以防止用户更改应该是不可变的内容。

您可以使用performance profilingbenchmarking来进一步了解程序的性能。

一旦你获得了切片的字节,fooBytes,它重新分配它不会分配一个新的数组,它只是分配一个新的切片,这是一个很小的。这似乎也是切割字符串的方式。

请注意,您不需要使用utf8包来计算utf8字符串中的单词,但如果您愿意,可以按照这种方式进行计数。 Go本地处理utf8。但是,如果要迭代字符,则无法将字符串表示为字节切片,因为您可以使用多字节字符。相反,你需要将它表示为一片符文:

foo := `here's my string`
fooRunes := []rune(foo)

根据我的经验,这种将字符串转换为符文片段的操作很快(我已经完成了基准测试,但可能会有分配)。现在你可以遍历fooRunes来计算单词,不需要utf8包。或者,您可以跳过显式的[]rune(foo)转换,并通过在字符串上使用for ... range循环隐式执行,因为这些是特殊的:

相反,对于范围循环,在每次迭代时解码一个UTF-8编码的符文。每次循环时,循环的索引是当前符文的起始位置,以字节为单位,代码点是其值。

- Strings, bytes, runes and characters in Go

以上是关于片段是否执行基础数据的复制?的主要内容,如果未能解决你的问题,请参考以下文章

VsCode 代码片段-提升研发效率

C++ 代码片段执行

有趣的 C++ 代码片段,有啥解释吗? [复制]

如何将数据从活动传输到片段? [复制]

Android:使用支持片段管理器时复制片段

这两个代码片段之间有区别吗?如果有,那又如何? [复制]