go中實(shí)現(xiàn)字符切片和字符串互轉(zhuǎn)
Go 1.21
// 返回一個(gè)Slice,它的底層數(shù)組自ptr開始,長度和容量都是len func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType // 返回一個(gè)指針,指向底層的數(shù)組 func SliceData(slice []ArbitraryType) *ArbitraryType // 生成一個(gè)字符串,底層的數(shù)組開始自ptr,長度是len // returns a string value whose underlying bytes start at ptr and whose length is len // The len argument must be of integer type or an untyped constant // A constant len argument must be non-negative and representable by a value of type int // if it is an untyped constant it is given type int // At run time, if len is negative, or if ptr is nil and len is not zero, a run-time panic occurs // Since Go strings are immutable, the bytes passed to String must not be modified afterwards func String(ptr *byte, len IntegerType) string // 返回字符串底層的數(shù)組 // returns a pointer to the underlying bytes of str // For an empty string the return value is unspecified, and may be nil. // Since Go strings are immutable, the bytes returned by StringData must not be modified. func StringData(str string) *byte
Go 1.20
廢棄兩個(gè)類型SliceHeader和StringHeader
Go 1.19
string.SliceHeader和string.StringHeader經(jīng)常用在 slice of byte 和 string 高效互轉(zhuǎn)場(chǎng)景
// go1.18.3/src/reflect/value.go // SliceHeader is the runtime representation of a slice. // It cannot be used safely or portably and its representation may // change in a later release. // Moreover, the Data field is not sufficient to guarantee the data // it references will not be garbage collected, so programs must keep // a separate, correctly typed pointer to the underlying data. type SliceHeader struct { Data uintptr Len int Cap int } // StringHeader is the runtime representation of a string. // It cannot be used safely or portably and its representation may // change in a later release. // Moreover, the Data field is not sufficient to guarantee the data // it references will not be garbage collected, so programs must keep // a separate, correctly typed pointer to the underlying data. type StringHeader struct { Data uintptr Len int }
Slice比String多一個(gè)Cap字段
兩個(gè)的數(shù)據(jù)都存儲(chǔ)在Data數(shù)組中
實(shí)現(xiàn)方式
方式1
string(bytes)或[]byte(str)
性能不佳
方式2
// toBytes performs unholy acts to avoid allocations func toBytes(s string) []byte { return *(*[]byte)(unsafe.Pointer(&s)) } // toString performs unholy acts to avoid allocations func toString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) }
方式3
func SliceByteToString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) } func StringToSliceByte(s string) []byte { x := (*[2]uintptr)(unsafe.Pointer(&s)) h := [3]uintptr{x[0], x[1], x[1]} return *(*[]byte)(unsafe.Pointer(&h)) }
方式4
func Clone(s string) string { if len(s) == 0 { return "" } b := make([]byte, len(s)) copy(b, s) return *(*string)(unsafe.Pointer(&b)) }
性能測(cè)試
var L = 1024 * 1024 var str = strings.Repeat("a", L) var s = bytes.Repeat([]byte{'a'}, L) var str2 string var s2 []byte func BenchmarkString2Slice(b *testing.B) { for i := 0; i < b.N; i++ { bt := []byte(str) if len(bt) != L { b.Fatal() } } } func BenchmarkString2SliceReflect(b *testing.B) { for i := 0; i < b.N; i++ { bt := *(*[]byte)(unsafe.Pointer(&str)) if len(bt) != L { b.Fatal() } } } func BenchmarkString2SliceUnsafe(b *testing.B) { for i := 0; i < b.N; i++ { bt := unsafe.Slice(unsafe.StringData(str), len(str)) if len(bt) != L { b.Fatal() } } } func BenchmarkSlice2String(b *testing.B) { for i := 0; i < b.N; i++ { ss := string(s) if len(ss) != L { b.Fatal() } } } func BenchmarkSlice2StringReflect(b *testing.B) { for i := 0; i < b.N; i++ { ss := *(*string)(unsafe.Pointer(&s)) if len(ss) != L { b.Fatal() } } } func BenchmarkSlice2StringUnsafe(b *testing.B) { for i := 0; i < b.N; i++ { ss := unsafe.String(unsafe.SliceData(s), len(str)) if len(ss) != L { b.Fatal() } } }
官方出品必然是好東西,所以相信GO1.21即可
到此這篇關(guān)于go中實(shí)現(xiàn)字符切片和字符串互轉(zhuǎn)的文章就介紹到這了,更多相關(guān)go字符切片和字符串互轉(zhuǎn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go 控制協(xié)程(goroutine)的并發(fā)數(shù)量
控制協(xié)程goroutine的并發(fā)數(shù)量是一個(gè)常見的需求,本文就來介紹一下Go 控制協(xié)程的并發(fā)數(shù)量,具有一定的參考價(jià)值,感興趣的可以了解一下2025-02-02Go打印結(jié)構(gòu)體提升代碼調(diào)試效率實(shí)例詳解
這篇文章主要介紹了Go打印結(jié)構(gòu)體提升代碼調(diào)試效率實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-02-02重學(xué)Go語言之?dāng)?shù)組的具體使用詳解
Go的數(shù)組是一種復(fù)合數(shù)據(jù)類型,在平時(shí)開發(fā)中并不常用,更常用的是切片(slice),可以把切片看作是能動(dòng)態(tài)擴(kuò)容的數(shù)組,切片的底層數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,所以數(shù)組雖不常用,但仍然有必要掌握2023-02-02基于Golang實(shí)現(xiàn)Redis協(xié)議解析器
這篇文章主要為大家詳細(xì)介紹了如何通過GO語言編寫簡單的Redis協(xié)議解析器,文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語言有一定的幫助,需要的可以參考一下2023-03-03基于go interface{}==nil 的幾種坑及原理分析
這篇文章主要介紹了基于go interface{}==nil 的幾種坑及原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04golang進(jìn)程在docker中OOM后hang住問題解析
這篇文章主要介紹了golang進(jìn)程在docker中OOM后hang住問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10golang中按照結(jié)構(gòu)體的某個(gè)字段排序?qū)嵗a
在任何編程語言中,關(guān)乎到數(shù)據(jù)的排序都會(huì)有對(duì)應(yīng)的策略,下面這篇文章主要給大家介紹了關(guān)于golang中按照結(jié)構(gòu)體的某個(gè)字段排序的相關(guān)資料,需要的朋友可以參考下2022-05-05