這是我參與更文挑戰的第 16 天,活動詳情查看: 更文挑戰mysql
上次咱們分享的內容咱回顧一下c++
要是對GO 對 ETCD 的編碼還有點興趣的話, 歡迎查看文章 GO 中 ETCD 的編碼案例分享sql
他是一種基本類型(string 類型
),而且是一個不可改變的UTF-8字符序列shell
在衆多編程語言裏面,相信都少不了字符串類型編程
字符串,顧名思義就是一串字符,咱們要明白,字符也是分爲中文字符和英文字符的數組
例如咱們在 C/C++
中 , 一個英文字符佔 1 個字節,一箇中文字符有的佔 2 個字節,有的佔3個字節markdown
用到 mysql
的中文字符,有的佔 4 個字節數據結構
回過來看 GO 裏面的字符串,字符也是根據英文和中文不同,一個字符所佔用的字節數也是不同的,大致分爲以下 2 種app
說到字符串的數據結構,咱們先來看看 GO 裏面的字符串,是在哪一個包裏面編程語言
不難發現,咱們隨便在 GOLANG 裏面 定義個string 變量
,就可以知道 string 類型是在哪一個包裏面,例如
var name string
複製代碼
GO 裏面的字符串對應的包是 builtin
// 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.
type string string
複製代碼
字符串這個類型,是全部8-bits
字符串的集合,一般但不必定表示utf -8
編碼的文本
字符串能夠爲空,但不能爲 nil
,此處的字符串爲空是 ""
字符串類型的值是不可變的
另外,找到 string
在 GO 裏面對應的源碼文件中src/runtime/string.go
, 有這麼一個結構體,只提供給包內使用,咱們能夠看到string
的數據結構 stringStruct
是這個樣子的
type stringStruct struct {
str unsafe.Pointer
len int
}
複製代碼
整個結構體,就 2 個成員,**string **類型是否是很簡單呢
是對應到字符串的首地址
這個就是不難理解,是字符串的長度
那麼,在建立一個字符串變量的時候,stringStruct
是在哪裏使用到的呢?
咱們看看 GO string.go 文件中的源碼
//go:nosplit
func gostringnocopy(str *byte) string {
ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)} // 構建成 stringStruct
s := *(*string)(unsafe.Pointer(&ss)) // 強轉成 string
return s
}
複製代碼
//go:nosplit
func findnull(s *byte) int {
if s == nil {
return 0
}
// Avoid IndexByteString on Plan 9 because it uses SSE instructions
// on x86 machines, and those are classified as floating point instructions,
// which are illegal in a note handler.
if GOOS == "plan9" {
p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
l := 0
for p[l] != 0 {
l++
}
return l
}
// pageSize is the unit we scan at a time looking for NULL.
// It must be the minimum page size for any architecture Go
// runs on. It's okay (just a minor performance loss) if the
// actual system page size is larger than this value.
const pageSize = 4096
offset := 0
ptr := unsafe.Pointer(s)
// IndexByteString uses wide reads, so we need to be careful
// with page boundaries. Call IndexByteString on
// [ptr, endOfPage) interval.
safeLen := int(pageSize - uintptr(ptr)%pageSize)
for {
t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
// Check one page at a time.
if i := bytealg.IndexByteString(t, 0); i != -1 {
return offset + i
}
// Move to next page
ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
offset += safeLen
safeLen = pageSize
}
}
複製代碼
簡單分爲 2 步:
從上述官方說明中,咱們能夠看到,字符串類型的值是不可變的
但是這是爲啥呢?
咱們之前在寫C/C++
的時候,爲啥能夠開闢空間存放多個字符,而且還能夠修改其中的某些字符呢?
但是在 C/C++
裏面的字面量也是不能夠改變的
GO 裏面的 string 類型,是否是也和 字面量同樣的呢?咱們來看看吧
字符串類型,自己也是擁有對應的內存空間的,那麼修改string
類型的值應該是要支持的。
但是,XDM
在 Go 的實現中,string
類型是不包含內存空間,只有一個內存的指針,這裏就有點想C/C++裏面的案例:
char * str = "XMTONG"
複製代碼
上述的 str
是絕對不能作修改的,str
只是做爲可讀,不能寫的
在GO 裏面的字符串,就與上述相似
這樣作的好處是 string
變得很是輕量,能夠很方便的進行傳遞而不用擔憂內存拷貝(這也避免了內存帶來的諸多問題)
GO 中的 string
類型通常是指向字符串字面量
字符串字面量存儲位置是在虛擬內存分區的只讀段上面,而不是堆或棧上
所以,GO 的 string
類型不可修改的
但是咱們想想,要是在GO 裏面字符串全都是隻讀的,那麼咱們如何動態修改一些咱們須要改變的字符呢,這豈不是缺陷了
別慌
GO 裏面還有byte數組,[]byte
這裏順帶說一下
上述 char * str = "XMTONG"
str
所佔字節數(C/C++中是經過 sizeof()
來計算的)的話,那就是 7 ,由於尾巴後面還有一個'\0'計算機中有這樣的對應關係,簡單提一下:
1 Bytes = 8 bit
1 K = 1024 Bytes
1 M = 1024 K
1 G = 1024 M
緣由正如上述咱們說到的,若是全是一些只讀的字面量,那麼咱們編碼的時候就沒得玩了
另外,也是根據使用字符串的場景緣由,單是string沒法知足全部的場景,所以得有一個咱們能夠修改裏面值的 []byte 來彌補一下
說到這裏,咱們應該就知道了,string
和[]byte
都是能夠表示字符串,沒毛病 ,
不過,他們畢竟對應不一樣的數據結構,使用方式也有必定的區別,GO 提供的對應方法也是不盡相同
咱們來看看什麼場景用 string 類型, 啥場景 使用 []byte 類型
使用到 string 類型的 地方:
nil
作比較,所以,不用到nil
的時候,也可使用 string 類型使用到 []byte 類型的 地方:
緣由以下:
看到這裏,分別瞭解了 string
類型, 和 []byte
類型的應用場景
毋庸置疑,咱們編碼過程當中,確定少不了對他們作相互轉換,咱們來看看在 GO ,裏面如何使用
package main
import (
"fmt"
)
func main(){
var str string
str = "XMTONG"
strByte := []byte(str)
for _,v :=range strByte{
fmt.Printf("%x ",v)
}
}
複製代碼
代碼輸出爲:
58 4d 54 4f 4e 47
複製代碼
上述代碼轉成 []byte
以後是一個字節,一個字節的
將每個字節的值用十六進制打印出來,咱們能夠看到,XMTONG
對應 584d544f4e47
[]byte
轉字符串在GO 裏面那就更簡單了
func main(){
name := []byte("XMTONG")
fmt.Println(string(name))
}
複製代碼
不管什麼語言,對於字符串大概涉及以下幾種操做,如有誤差,還請指正:
具體的函數使用方法也比較簡單,推薦你們感興趣的能夠直接看go 的開發文檔,須要的時候去查一下便可。
GO 的標準開發文檔,在搜索引擎裏面仍是比較容易搜索到的
[]byte
的由來和應用場景[]byte
相互轉換朋友們,你的支持和鼓勵,是我堅持分享,提升質量的動力
好了,本次就到這裏,下一次 GO 中 slice 的實現原理分享
技術是開放的,咱們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。
我是小魔童哪吒,歡迎點贊關注收藏,下次見~