golang string與byte的區別

2021-08-15 19:42:09 字數 3242 閱讀 3073

為啥string和byte型別轉換需要一定的代價?

為啥內建函式copy會有一種特殊情況copy(dst byte, src string) int?

string和byte,底層都是陣列,但為什麼byte比string靈活,拼接效能也更高(動態字串拼接效能對比)?

今天看了原始碼**了一下。

以下所有觀點都是個人愚見,有不同建議或補充的的歡迎emial我aboutme

什麼是字串?標準庫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
func gostringnocopy(str *byte) string 

s := *(*string)(unsafe.pointer(&ss))

return s

}

哈哈,其實就是byte陣列,而且要注意string其實就是個struct。

首先在go裡面,byte是uint8的別名。而slice結構在go的原始碼中src/runtime/slice.go定義:

type slice struct
array是陣列的指標,len表示長度,cap表示容量。除了cap,其他看起來和string的結構很像。

但其實他們差別真的很大。

字串的值是不能改變

在前面說到了字串的值是不能改變的,這句話其實不完整,應該說字串的值不能被更改,但可以被替換。 還是以string的結構體來解釋吧,所有的string在底層都是這樣的乙個結構體stringstruct,string結構體的str指標指向的是乙個字元常量的位址, 這個位址裡面的內容是不可以被改變的,因為它是唯讀的,但是這個指標可以指向不同的位址,我們來對比一下string、byte型別重新賦值的區別:

s := "a1" // 分配儲存"a1"的記憶體空間,s結構體裡的str指標指向這快記憶體

s = "a2" // 重新給"a2"的分配記憶體空間,s結構體裡的str指標指向這快記憶體

其實byte和string的差別是更改變數的時候array的內容可以被更改。

s := byte // 分配儲存1陣列的記憶體空間,s結構體的array指標指向這個陣列。

s = byte // 將array的內容改為2

因為string的指標指向的內容是不可以更改的,所以每更改一次字串,就得重新分配一次記憶體,之前分配空間的還得由gc**,這是導致string操作低效的根本原因。

string和byte的相互轉換

將string轉為byte,語法byte(string)原始碼如下:

func stringtoslicebyte(buf *tmpbuf, s string) byte 

b = buf[:len(s)]

} else

copy(b, s)

return b

}func rawstring(size int) (s string, b byte)

return

}

可以看到b是新分配的,然後再將s複製給b,至於為啥copy函式可以直接把string複製給byte,那是因為go原始碼單獨實現了乙個slicestringcopy函式來實現,具體可以看src/runtime/slice.go

將byte轉為string,語法string(byte)原始碼如下:

func slicebytetostring(buf *tmpbuf, b byte) string 

if raceenabled && l > 0

if msanenabled && l > 0

s, c := rawstringtmp(buf, l)

copy(c, b)

return s

}func rawstringtmp(buf *tmpbuf, l int) (s string, b byte) else

return

}

依然可以看到s是新分配的,然後再將b複製給s。

正因為string和byte相互轉換都會有新的記憶體分配,才導致其代價不小,但讀者千萬不要誤會,對於現在的機器來說這些代價其實不值一提。 但如果想要頻繁string和byte相互轉換(僅假設),又不會有新的記憶體分配,能有辦法嗎?答案是有的。

package string_slicebyte_test

import (

"log"

"reflect"

"testing"

"unsafe"

)func stringtoslicebyte(s string) byte

return *(*byte)(unsafe.pointer(&bh))

}func slicebytetostring(b byte) string

return *(*string)(unsafe.pointer(&sh))

}func teststringslicebyte(t *testing.t)

答案雖然有,但強烈推薦不要使用這種方法來轉換型別,因為如果通過stringtoslicebyte將string轉為byte的時候,共用的時同一塊記憶體,原先的string記憶體區域是唯讀的,一但更改將會導致整個程序down掉,而且這個錯誤是runtime沒法恢復的。

既然string就是一系列位元組,而byte也可以表達一系列位元組,那麼實際運用中應當如何取捨?

最後脫離場景談效能都是耍流氓,需要根據實際場景來抉擇。

GoLang string及其相關操作

str hello world n hello gopher n 輸出 hello world hello gopher str hello world n hello gopher n 輸出 hello world nhello gopher n 雙引號中的轉義字元被替換,而反引號中原生字串中的 ...

golang string迭代和結構體初始化

1.golang字串range時返回的型別為rune 在某次測試時發現,string字串,直接用下標訪問和用range訪問返回的型別不同,參看下面 func main 輸出結果為 type is uint8 is type int32 is type int32即直接下標訪問和用range訪問返回的...

golang string轉json的一些坑

大佬們都知道怎麼在string中給string型別賦值帶雙引號的字串,沒錯就是用反斜槓,如下 msg 但是golang還支援另外乙個符號,我初學時候以為是單引號,但其實不是,是esc鍵下邊那個,那麼賦值帶雙引號的字串就如下就行了 ret 先看一段 起作用是把字串轉換為結構體對應的json type ...