• go的字符切片和字符串互转


    Go 1.21

    // 返回一个Slice,它的底层数组自ptr开始,长度和容量都是len
    func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
    // 返回一个指针,指向底层的数组
    func SliceData(slice []ArbitraryType) *ArbitraryType
    // 生成一个字符串,底层的数组开始自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
    // 返回字符串底层的数组
    // 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Go 1.20

    废弃两个类型SliceHeader和StringHeader

    Go 1.19

    string.SliceHeader和string.StringHeader经常用在 slice of byte 和 string 高效互转场景

    // 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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    Slice比String多一个Cap字段
    两个的数据都存储在Data数组中

    方式

    方式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))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    方式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))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    方式4

    func Clone(s string) string {
    	if len(s) == 0 {
    		return ""
    	}
    	b := make([]byte, len(s))
    	copy(b, s)
    	return *(*string)(unsafe.Pointer(&b))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    性能测试

    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()
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    官方出品必然是好东西,所以相信GO1.21即可

    参考

    https://colobu.com/2022/09/06/string-byte-convertion/
    https://pkg.go.dev/unsafe#String

  • 相关阅读:
    MySQL、redis、MongoDB、elasticsearch的对比
    14. happens-before模型
    ABAB OpenSQL 分页处理
    07 | @Entity 之间的关联关系注解如何正确使用?
    leetcode 12. Integer to Roman(整数转罗马数字)
    Android 11适配
    Store:海量实用工具,让工作更加高效,更加轻松!
    vue封装一个查询URL参数方法
    java学习day31(redis11)主从复制
    k8s集群-7 service
  • 原文地址:https://blog.csdn.net/wangkai6666/article/details/134496694