go中实现字符切片和字符串互转

 更新时间:2023年11月20日 09:47:50   作者:~kiss~  
这篇文章主要为大家详细介绍了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

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
}

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))
}

方式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))
}

性能测试

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即可

到此这篇关于go中实现字符切片和字符串互转的文章就介绍到这了,更多相关go字符切片和字符串互转内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言常用字符串处理方法实例汇总

    Go语言常用字符串处理方法实例汇总

    这篇文章主要介绍了Go语言常用字符串处理方法,实例汇总了Go语言中常见的各种字符串处理技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • Go 控制协程(goroutine)的并发数量

    Go 控制协程(goroutine)的并发数量

    控制协程goroutine的并发数量是一个常见的需求,本文就来介绍一下Go 控制协程的并发数量,具有一定的参考价值,感兴趣的可以了解一下
    2025-02-02
  • Go打印结构体提升代码调试效率实例详解

    Go打印结构体提升代码调试效率实例详解

    这篇文章主要介绍了Go打印结构体提升代码调试效率实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-02-02
  • 重学Go语言之数组的具体使用详解

    重学Go语言之数组的具体使用详解

    Go的数组是一种复合数据类型,在平时开发中并不常用,更常用的是切片(slice),可以把切片看作是能动态扩容的数组,切片的底层数据结构就是数组,所以数组虽不常用,但仍然有必要掌握
    2023-02-02
  • 基于Golang实现Redis协议解析器

    基于Golang实现Redis协议解析器

    这篇文章主要为大家详细介绍了如何通过GO语言编写简单的Redis协议解析器,文中的示例代码讲解详细,对我们深入了解Go语言有一定的帮助,需要的可以参考一下
    2023-03-03
  • 基于go interface{}==nil 的几种坑及原理分析

    基于go interface{}==nil 的几种坑及原理分析

    这篇文章主要介绍了基于go interface{}==nil 的几种坑及原理分析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • golang fmt格式“占位符”的实例用法详解

    golang fmt格式“占位符”的实例用法详解

    在本篇文章里小编给大家整理的是一篇关于golang fmt格式“占位符”的实例用法详解内容,有兴趣的朋友们可以学习下。
    2021-07-07
  • golang进程在docker中OOM后hang住问题解析

    golang进程在docker中OOM后hang住问题解析

    这篇文章主要介绍了golang进程在docker中OOM后hang住问题解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • golang中按照结构体的某个字段排序实例代码

    golang中按照结构体的某个字段排序实例代码

    在任何编程语言中,关乎到数据的排序都会有对应的策略,下面这篇文章主要给大家介绍了关于golang中按照结构体的某个字段排序的相关资料,需要的朋友可以参考下
    2022-05-05
  • Go通道channel通过通信共享内存

    Go通道channel通过通信共享内存

    这篇文章主要为大家介绍了Go通道channel通过通信共享内存示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07

最新评论