ChatGPT解决这个技术问题 Extra ChatGPT

如何将字符串分配给字节数组

go

我想将字符串分配给字节数组:

var arr [20]byte
str := "abc"
for k, v := range []byte(str) {
  arr[k] = byte(v)
}

有别的方法吗?

如果 str 的长度大于 arr 的长度,那么您将收到“索引超出范围”错误。
[]byte(“abc”) 将字符串设置为字节切片。请参阅 stackoverflow.com/a/62740786/12817546.string(b)fmt.Sprintf("%s", b) 将字节切片设置为字符串。见stackoverflow.com/a/62725637/12817546

o
openwonk

安全简单:

[]byte("Here is a string....")

在将字符串转换为字节时,Go 中的最佳编码实践是使用字节切片 []byte不是一组字节 [20]byte...不相信我吗?查看 Rob Pike 在 this thread 上的回答
OP 询问的是一个数组,而不是一个切片。在某些情况下,您需要限制切片的大小并改用数组。我在下面的回答会修剪多余的字符以确保您不会溢出数组。
对于那些认为这看起来有点奇怪的人:这只是 Go 中的类型转换:golang.org/ref/spec#Conversions
有什么方法可以添加多个字符串并将它们连接起来?例如[]byte("one", "two")
不幸的是,@rakim,您只能传递一个字符串...因此,您必须先将它们连接起来或组合多个字节切片(超出此问题的范围)。
A
Alexander

要将字符串转换为字节切片,string -> []byte

[]byte(str)

要将数组转换为切片,[20]byte -> []byte

arr[:]

要将字符串复制到数组,string -> [20]byte

copy(arr[:], str)

与上面相同,但首先将字符串显式转换为切片:

copy(arr[:], []byte(str))

内置的复制功能仅从切片复制到切片。

数组是“底层数据”,而切片是“底层数据的视口”。

使用 [:] 使数组符合切片的条件。

字符串不符合可以复制到的切片的条件,但它可以作为可以复制的切片(字符串是不可变的)。

如果字符串太长,则 copy 将只复制适合的部分字符串(然后可能只复制部分多字节符文,这将破坏结果字符串的最后一个符文)。

这段代码:

var arr [20]byte
copy(arr[:], "abc")
fmt.Printf("array: %v (%T)\n", arr, arr)

...给出以下输出:

array: [97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] ([20]uint8)

我还在 Go Playground


您可能想添加一个转换单个字符的示例。我由此推断 b[i] = []byte("A")[0] 有效,但 b[i] = 'A' 最终变得更干净。
这不适用于多字节符文:b[1] = '本'
一个没有人回答的问题仍然悬而未决:[]byte(str) 是否使用 make() 创建新的底层数组?还是只是将指针副本返回到原始字符串。
@Nulik 使用 godbolt.org 我看到 []byte(str) 调用了 runtime.stringtoslicebyte 函数。 stringtoslicebyte 将在需要时分配内存,然后调用 copy。见:string.gocopy 函数循环复制字节。
p
peterSO

例如,

package main

import "fmt"

func main() {
    s := "abc"
    var a [20]byte
    copy(a[:], s)
    fmt.Println("s:", []byte(s), "a:", a)
}

输出:

s: [97 98 99] a: [97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

这是唯一真正解决原始问题的答案。
为什么要分配 20 个字节而不是具体说明您实际需要的字符串?如果字符串需要少于 20 是不是有点低效?如果超过 20 也容易出错?
@Sir:我们不分配 20 个字节。我们复制3个字节,长度为s,`copy函数不傻。 Appending to and copying slices:“复制的元素数量是 len(src) 和 len(dst) 中的最小值。”
S
Sameh Sharaf

小菜一碟:

arr := []byte("That's all folks!!")

这似乎没有回答这个问题。 OP 想要将字符串的字节写入可能比字符串长的现有数组。
使用切片 []byte 优于数组 [20]byte。根据最佳实践,答案是正确的;如果规范或代码需要数组,则使用 copy 代替(请参阅此线程中其他地方的示例)。
c
chespinoza

我觉得这样更好。。

package main

import "fmt"

func main() {
    str := "abc"
    mySlice := []byte(str)
    fmt.Printf("%v -> '%s'",mySlice,mySlice )
}

在这里检查:http://play.golang.org/p/vpnAWHZZk7


这不是更好。这是错的。它没有做问题所要求的。
A
ASHWIN RAJEEV

Go,将字符串转换为字节切片

您需要一种将 []string 转换为 []byte 类型的快速方法。用于将文本数据存储到随机访问文件或其他需要输入数据为 []byte 类型的数据操作的情况。

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

这在使用 ioutil.WriteFile 时很有用,它接受字节切片作为其数据参数:

WriteFile func(filename string, data []byte, perm os.FileMode) error

另一个例子

package main

import (
    "fmt"
    "strings"
)

func main() {

    stringSlice := []string{"hello", "world"}

    stringByte := strings.Join(stringSlice, " ")

    // Byte array value
    fmt.Println([]byte(stringByte))

    // Corresponding string value
    fmt.Println(string([]byte(stringByte)))
}

输出:

[104 101 108 108 111 32 119 111 114 108 100] 你好,世界

请检查链接 playground


D
DavidGamba

最终创建了特定于数组的方法来执行此操作。很像 encoding/binary 包,每个 int 类型都有特定的方法。例如 binary.BigEndian.PutUint16([]byte, uint16)

func byte16PutString(s string) [16]byte {
    var a [16]byte
    if len(s) > 16 {
        copy(a[:], s)
    } else {
        copy(a[16-len(s):], s)
    }
    return a
}

var b [16]byte
b = byte16PutString("abc")
fmt.Printf("%v\n", b)

输出:

[0 0 0 0 0 0 0 0 0 0 0 0 0 97 98 99]

请注意我想要在左侧而不是右侧进行填充。

http://play.golang.org/p/7tNumnJaiN


我认为反对票是因为 byte16PutString 是内置 copy 函数的一种重新实现,它只支持创建新数组而不是使用现有数组。 copy 具有特殊的编译器支持,因此它可以处理不同类型的参数,并且它可能具有真正的高性能实现。此外,OP 的问题询问关于将字符串写入现有数组,而不是分配新数组,尽管大多数其他答案似乎也忽略了这一点......
m
mroman

数组是值......切片更像是指针。那就是 [n]type[]type 不兼容,因为它们本质上是两个不同的东西。您可以使用 arr[:] 获取指向数组的切片,该切片返回具有 arr 作为后备存储的切片。

将例如 []byte 的切片转换为 [20]byte 的一种方法是实际分配一个 [20]byte,您可以使用 var [20]byte 来执行此操作(因为它是一个值......不需要 make)然后复制数据进入它:

buf := make([]byte, 10)
var arr [10]byte
copy(arr[:], buf)

本质上,许多其他答案出错的是 []type 不是数组。

[n]T[]T 是完全不同的东西!

当使用反射时,[]T 不是一种数组,而是一种 Slice,而 [n]T 是一种数组。

您也不能使用 map[[]byte]T,但可以使用 map[[n]byte]T

这有时会很麻烦,因为很多函数都在 []byte 上运行,而有些函数返回 [n]byte(最值得注意的是 crypto/* 中的哈希函数)。例如,sha256 哈希是 [32]byte 而不是 []byte,因此当初学者尝试将其写入文件时,例如:

sum := sha256.Sum256(data)
w.Write(sum)

他们会得到一个错误。的正确方法是使用

w.Write(sum[:])

然而,你想要的是什么?只是按字节访问字符串?您可以使用以下方法轻松地将 string 转换为 []byte

bytes := []byte(str)

但这不是一个数组,而是一个切片。此外,byte != rune。如果您想对“字符”进行操作,您需要使用 rune... 而不是 byte


B
Brandon Gao

除了上面提到的方法,你还可以做一个技巧

s := "hello"
b := *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s))))

去玩:http://play.golang.org/p/xASsiSpQmC

你永远不应该使用这个:-)


这太疯狂了。我认为值得在您的回复末尾添加“但您不应该”。除了它并没有真正回答问题之外(OP 谈论字节数组,而不是切片),您似乎没有使用“转换”获得正确的 []byte 对象 - 当您尝试修改时它会严重失败p,参见:play.golang.org/p/WHGl756ucj。在您的情况下,不确定为什么您更喜欢双重不安全而不是 b := []byte(s) 方法。
@tomasz 我不喜欢以这种方式执行 string <-> []byte ,只是显示一个不同的选项:-) 是的,你是对的,我误解了这个问题。
当我这样做时,结果有一个任意大小的 cap(),这意味着它正在读入未知内存。为此,我认为您需要确保分配完整的 reflect.SliceHeader 大小并手动设置 cap。像这样的东西:play.golang.org/p/fBK4dZM-qD
我什至不确定。-------------^-- 也许这样更好:play.golang.org/p/NJUxb20FTG
我同意你可能不应该这样做,但理论上原因是为了避免分配。 []byte(str) 分配一个副本(编译器可以优化和消除副本的某些情况除外)