谁能给通俗的讲讲[]byte和string的区别,新手一直没弄明白这个问题

看很多函数都使用[]byte作为参数或返回值,但有的函数内部又有许多 string和[]byte的互相转换 这两者到底有什么区别?或者说什么时候应该使用[]byte,什么时候用string? 目前已知的信息 string类型是不可变的 不可使用数组下标进行修改 []byte和string的互相转换得到的是一个拷贝,会得到不同的内存地址

望高手能给通俗的讲讲,谢谢

已邀请:

caibirdme - a green bird

赞同来自: liushuchun gloomyzerg mnhkahn henrylee2cn Xargin yulibaozi tangmo tanteng更多 »

在源码里,string的定义如下:

type stringStruct struct {
    str unsafe.Pointer
    len int
}

可以看到str其实是个指针,指向某个数组的首地址,写过c的话应该很好理解。 到底某个数组是什么呢? 在实例化这个stringStruct的时候:

func gostringnocopy(str *byte) string {
    ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
    //...
}

你应该可以看出个所以然。

但是在go里应该注意到,[]byte从C的角度来看是个数组,但其实是slice,slice和数组不一样的地方是,slice是一个封装了数组的结构体,所以var arr []byte的首地址不是&arr[0]

相关的你可以看看源码中的runtime,所以如果对性能有要求,[]byte肯定是比string快的

傅小黑

赞同来自: gloomyzerg cathywife tangmo

我觉得换个想法,[]byte 就是纯粹字节数据,string 是字符串数据。 区别就是你怎么看待你获得的数据。 比如抓网页的内容,可以认为是 string,用 strings 包的方法 比如解析socket协议内容,可以认为就是字节数据 []byte,用 bytes 包的方法,有时候可能需要单个 byte 的操作

pathbox - https://pathbox.github.io/

赞同来自: buscoop polar9527

string 给人看的

bytes 给程序看的

bit 0/1 给计算机看的

flw

赞同来自: gloomyzerg

我说说我的一些理解。

首先,从语言设计的层面来讲,Go 语言得有字符串吧?别的语言都有 Go 要是没有这也不合适,这就是 string 类型的来源。

然后,从基本类型的角度考虑,整数有不同的宽度,所以 int int8 int16 int32 int64 这些都得有,相应的无符号版本 uint uint8 uint16 uint32 uint64 也都有。

byte 其实只不过是 uint8 的一个别名,两者之间任何时候都是互相等价的。

$ go doc builtin.byte
type byte byte
    byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
    used, by convention, to distinguish byte values from 8-bit unsigned integer
    values.

再往后,数组你得有吧?于是就有了 []byte。当然,也有了 []string,这都是顺理成章的事情。

因此,从语法角度来看,[]bytestring 并不存在相互竞争或者相互对立的问题,这都是一个语言自然而然就会有的东西。

我们知道,string 就是一系列字节,这个文档中也有讲到(特别注意最后一句提到 string 值是不可改变的):

$ go doc builtin.string
type string string
    string is the set of all strings of 8-bit bytes, conventionally but not
    necessarily representing UTF-8-encoded text. A string may be empty, but not
    nil. Values of string type are immutable.

那么真正的问题来自于它们两者在使用时的区别。 既然 string 就是一系列字节,而 []byte 也可以表达一系列字节,那么实际运用中应当如何取舍?

  • string 值不可修改,所以每次修改时会创建一个新的 string,要想原地修改就只能用 []byte
  • string 值不可为 nil,所以如果你想要通过返回 nil 表达点什么额外的含义,就只能用 []byte
  • []byte 可以是数组也可以是切片,Go 语言的切片这么灵活,想要用切片的特性就只能用 []byte
  • 如果你要调用第三方库,如果第三方库主要用的是 string,那么为了避免频繁的进行类型转换,那你就可以用 string。毕竟 Go 是强类型语言,类型转换会极大地降低代码的可读性。[]byte 也是同理。
  • 需要进行字符串处理的时候,因为 []byte 支持切片,并且可以原地修改,所以 string 更快一些,所以注重性能的地方你可以用 []byte

暂时就先总结这么多,欢迎大家补充。

Xanthus - 红红火火恍恍惚惚

赞同来自: damao

可以把string转成[]byte遍历看一下, 再直接range一下string看看。 个人感觉最大区别就是对特殊字符的处理,一个rune不一定对应一个byte,但对应一个字符

mnhkahn - Bryce Li

赞同来自:

对于字符串的操作尽量用[]byte来做,bytes包支持的功能和strings的差不多。

对于字符串是常量,修改会重新分配,性能不如[]byte

qiyin

赞同来自:

引用一段 《string 优化误区及建议》 我认为这篇文章可以解答你的疑惑

【Go】string 优化误区及建议 原文链接: https://blog.thinkeridea.com/201902/go/string_ye_shi_yin_yong_lei_xing.html

本文原标题为 《string 也是引用类型》,经过 郝林 大佬指点原标题存在诱导性,这里解释一下 "引用类型" 有两个特征:1、多个变量引用一块内存数据,不创建变量的副本,2、修改任意变量的数据,其它变量可见。显然字符串只满足了 "引用类型" 的第一个特点,不能满足第二个特点,顾不能说字符串是引用类型,感谢大佬指正。

初学 Go 语言的朋友总会在传 []byte 和 string 之间有着很多纠结,实际上是没有了解 string 与 slice 的本质,而且读了一些程序源码,也发现很多与之相关的问题,下面类似的代码估计很多初学者都写过,也充分说明了作者当时内心的纠结:

xiaoma

赞同来自:

byte 是uint8,只能表示ASCII字符,如果只是操作英文字符串和一般标点符号,可以用byte 若含有汉字、日文,用rune,rune是uint32 否则用string转化会出现意外

ws1992go - 90后运维工程师

赞同来自:

string 在底层实质上是 byte 型数组。字符串是不可变字节序列,他可以包含任意数据,包括0值字节,主要是人类可读。 []byte 在系统调用,例如读写文件,JSON 序列化与反序列化;进程间通信,例如远程 tcp,REST API 调用。

jdlau - https://www.jdscript.com/

赞同来自:

据我所知,[]byte多用来做流传输。

要回复问题请先登录注册