以下由golang教學專欄為大家介紹golang string和[]byte的比較區別,希望對需要的朋友有幫助!
golang string和[]byte的比較
為啥string和[]byte型別轉換需要一定的代價?
為啥內建函數copy會有一種特殊情況copy(dst []byte, src string) int
?
string和[]byte,底層都是數組,但為什麼[]byte比string靈活,拼接性能也更高(動態字串拼接性能對比)?
今天看了源碼探究了一下。
以下所有觀點都是個人愚見,有不同建議或補充的的歡迎emial我aboutme
何為string?
什麼是字串?標準函式庫builtin
的解釋:
type 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.
簡單的來說字串是一系列8位元組的集合,通常但不一定代表UTF-8編碼的文字。字串可以為空,但不能為nil。而且字串的值是不能改變的。
不同的語言字串有不同的實現,在go的源碼中src/runtime/string.go
,string的定義如下:
type stringStruct struct { str unsafe.Pointer len int}
可以看到str其實是個指針,指向某個數組的首地址,另一個字段是len長度。那到這個陣列是什麼呢?在實例化這個stringStruct的時候:
func gostringnocopy(str *byte) string { ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)} s := *(*string)(unsafe.Pointer(&ss)) return s }
哈哈,其實就是byte數組,而且要注意string其實就是個struct。
何為[]byte?
首先在go裡面,byte是uint8的別名。而slice結構在go的原始碼中src/runtime/slice.go
定義:
type slice struct { array unsafe.Pointer len int cap int}
array是数组的指针,len表示长度,cap表示容量。除了cap,其他看起来和string的结构很像。
但其实他们差别真的很大。
区别
字符串的值是不能改变
在前面说到了字符串的值是不能改变的,这句话其实不完整,应该说字符串的值不能被更改,但可以被替换。 还是以string的结构体来解释吧,所有的string在底层都是这样的一个结构体stringStruct{str: str_point, len: str_len}
,string结构体的str指针指向的是一个字符常量的地址, 这个地址里面的内容是不可以被改变的,因为它是只读的,但是这个指针可以指向不同的地址,我们来对比一下string、[]byte类型重新赋值的区别:
s := "A1" // 分配存储"A1"的内存空间,s结构体里的str指针指向这快内存 s = "A2" // 重新给"A2"的分配内存空间,s结构体里的str指针指向这快内存
其实[]byte和string的差别是更改变量的时候array的内容可以被更改。
s := []byte{1} // 分配存储1数组的内存空间,s结构体的array指针指向这个数组。s = []byte{2} // 将array的内容改为2
因为string的指针指向的内容是不可以更改的,所以每更改一次字符串,就得重新分配一次内存,之前分配空间的还得由gc回收,这是导致string操作低效的根本原因。
string和[]byte的相互转换
将string转为[]byte,语法[]byte(string)
源码如下:
func stringtoslicebyte(buf *tmpBuf, s string) []byte { var b []byte if buf != nil && len(s) <p style="margin: 30px 0; color: rgba(64, 64, 64, 1); font-family: Lora, " times new roman serif font-size: font-style: normal font-weight: text-indent: background-color: rgba>可以看到b是新分配的,然后再将s复制给b,至于为啥copy函数可以直接把string复制给[]byte,那是因为go源码单独实现了一个<code style="font-family: Menlo, Monaco, Consolas, " courier new monospace font-size: padding: color: rgba background-color: border-radius:>slicestringcopy</code>函数来实现,具体可以看<code style="font-family: Menlo, Monaco, Consolas, " courier new monospace font-size: padding: color: rgba background-color: border-radius:>src/runtime/slice.go</code>。</p><p style="margin: 30px 0; color: rgba(64, 64, 64, 1); font-family: Lora, " times new roman serif font-size: font-style: normal font-weight: text-indent: background-color: rgba>将[]byte转为string,语法<code style="font-family: Menlo, Monaco, Consolas, " courier new monospace font-size: padding: color: rgba background-color: border-radius:>string([]byte)</code>源码如下:</p><pre style="font-family: Menlo, Monaco, Consolas, " courier new monospace font-size: display: block padding: margin: color: rgba background-color: border: solid border-radius: font-style: normal font-weight: text-indent:>func slicebytetostring(buf *tmpBuf, b []byte) string { l := len(b) if l == 0 { // Turns out to be a relatively common case. // Consider that you want to parse out data between parens in "foo()bar", // you find the indices and convert the subslice to string. return "" } if raceenabled && l > 0 { racereadrangepc(unsafe.Pointer(&b[0]), uintptr(l), getcallerpc(unsafe.Pointer(&buf)), funcPC(slicebytetostring)) } if msanenabled && l > 0 { msanread(unsafe.Pointer(&b[0]), uintptr(l)) } s, c := rawstringtmp(buf, l) copy(c, b) return s }func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) { if buf != nil && l <p style="margin: 30px 0; color: rgba(64, 64, 64, 1); font-family: Lora, " times new roman serif font-size: font-style: normal font-weight: text-indent: background-color: rgba>依然可以看到s是新分配的,然后再将b复制给s。<br>正因为string和[]byte相互转换都会有新的内存分配,才导致其代价不小,但读者千万不要误会,对于现在的机器来说这些代价其实不值一提。 但如果想要频繁string和[]byte相互转换(仅假设),又不会有新的内存分配,能有办法吗?答案是有的。</p><pre style="font-family: Menlo, Monaco, Consolas, " courier new monospace font-size: display: block padding: margin: color: rgba background-color: border: solid border-radius: font-style: normal font-weight: text-indent:>package string_slicebyte_testimport ( "log" "reflect" "testing" "unsafe")func stringtoslicebyte(s string) []byte { sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) bh := reflect.SliceHeader{ Data: sh.Data, Len: sh.Len, Cap: sh.Len, } return *(*[]byte)(unsafe.Pointer(&bh)) }func slicebytetostring(b []byte) string { bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) sh := reflect.StringHeader{ Data: bh.Data, Len: bh.Len, } return *(*string)(unsafe.Pointer(&sh)) }func TestStringSliceByte(t *testing.T) { s1 := "abc" b1 := []byte("def") copy(b1, s1) log.Println(s1, b1) s := "hello" b2 := stringtoslicebyte(s) log.Println(b2) // b2[0] = byte(99) unexpected fault address b3 := []byte("test") s3 := slicebytetostring(b3) log.Println(s3) }
答案虽然有,但强烈推荐不要使用这种方法来转换类型,因为如果通过stringtoslicebyte将string转为[]byte的时候,共用的时同一块内存,原先的string内存区域是只读的,一但更改将会导致整个进程down掉,而且这个错误是runtime没法恢复的。
如何取舍?
既然string就是一系列字节,而[]byte也可以表达一系列字节,那么实际运用中应当如何取舍?
- string可以直接比较,而[]byte不可以,所以[]byte不可以当map的key值。
- 因为无法修改string中的某个字符,需要粒度小到操作一个字符时,用[]byte。
- string值不可为nil,所以如果你想要通过返回nil表达额外的含义,就用[]byte。
- []byte切片这么灵活,想要用切片的特性就用[]byte。
- 需要大量字符串处理的时候用[]byte,性能好很多。
最后脱离场景谈性能都是耍流氓,需要根据实际场景来抉择。
更多golang相关技术文章,请访问go语言栏目!
以上是詳解golang string和[]byte的對比的詳細內容。更多資訊請關注PHP中文網其他相關文章!

go语言有缩进。在go语言中,缩进直接使用gofmt工具格式化即可(gofmt使用tab进行缩进);gofmt工具会以标准样式的缩进和垂直对齐方式对源代码进行格式化,甚至必要情况下注释也会重新格式化。

本篇文章带大家了解一下golang 的几种常用的基本数据类型,如整型,浮点型,字符,字符串,布尔型等,并介绍了一些常用的类型转换操作。

go语言叫go的原因:想表达这门语言的运行速度、开发速度、学习速度(develop)都像gopher一样快。gopher是一种生活在加拿大的小动物,go的吉祥物就是这个小动物,它的中文名叫做囊地鼠,它们最大的特点就是挖洞速度特别快,当然可能不止是挖洞啦。

是,TiDB采用go语言编写。TiDB是一个分布式NewSQL数据库;它支持水平弹性扩展、ACID事务、标准SQL、MySQL语法和MySQL协议,具有数据强一致的高可用特性。TiDB架构中的PD储存了集群的元信息,如key在哪个TiKV节点;PD还负责集群的负载均衡以及数据分片等。PD通过内嵌etcd来支持数据分布和容错;PD采用go语言编写。

在写 Go 的过程中经常对比这两种语言的特性,踩了不少坑,也发现了不少有意思的地方,下面本篇就来聊聊 Go 自带的 HttpClient 的超时机制,希望对大家有所帮助。

go语言需要编译。Go语言是编译型的静态语言,是一门需要编译才能运行的编程语言,也就说Go语言程序在运行之前需要通过编译器生成二进制机器码(二进制的可执行文件),随后二进制文件才能在目标机器上运行。

删除map元素的两种方法:1、使用delete()函数从map中删除指定键值对,语法“delete(map, 键名)”;2、重新创建一个新的map对象,可以清空map中的所有元素,语法“var mapname map[keytype]valuetype”。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Dreamweaver CS6
視覺化網頁開發工具

禪工作室 13.0.1
強大的PHP整合開發環境

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載
最受歡迎的的開源編輯器