一文详解Go语言字符串

文章目录

Go语言字符串的本质

Go 语言字符串本质是指向一串一段只读的 UTF-8 字节序列的描述符

两个关键

  • 只读
  • UTF-8 编码的字节序列

内存结构

在 Go 的源码中(具体可见 runtime/string.go)

复制代码
type stringStruct struct {  
    str unsafe.Pointer  
    len int  
}
层面 原因 说明
UTF-8 编码 变长结构,无法安全修改部分字节 改动一个字节可能破坏整个字符
Go 语言设计 字符串不可变 保证安全、高效、可共享
修改方式 转为 []rune[]byte 才能进行内容更改

和其他类型的转换(内存结构的变化)

转[]rune

Unicode 规定"编号",UTF 编码规定"存法"。

Unicode 像身份证号体系,UTF 像不同格式的数据库存储规则。

转换方向 语法 说明
string → []rune runes := []rune(str) 将字符串解码成 Unicode 码点切片
[]rune → string str := string(runes) 将 Unicode 码点重新编码成 UTF-8 字符串
string → []rune 实现的具体逻辑见 func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune
内容 string []rune 备注
每个字符占用 1~4 字节(UTF-8) 4 字节(int32) rune 固定 4 字节
是否分配新内存 ✅ 是 转换时分配新切片
可否修改 ✅ 可以 string 只读
是否引用同一底层数据 ❌ 否 ❌ 否 完全新分配
go 复制代码
func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {  
    // two passes.  
    // unlike slicerunetostring, no race because strings are immutable.    n := 0  
    for range s {  
       n++  
    }  
  
    var a []rune  
    if buf != nil && n <= len(buf) {  
       *buf = [tmpStringBufSize]rune{}  
       a = buf[:n]  
    } else {  
       a = rawruneslice(n)  
    }  
  
    n = 0  
    for _, r := range s {  
       a[n] = r  
       n++  
    }  
    return a  
}

转 []bytes

转换方向 操作 是否分配新内存 是否复制 安全性
string → []byte []byte(s) ✅ 是 ✅ 是 ✅ 安全
[]byte → string string(b) ✅ 是 ✅ 是 ✅ 安全

测试代码

go 复制代码
func string_impl() {
    s1 := "My name is 张朝阳"
    arr := []byte(s1)
    brr := []rune(s1)
    fmt.Printf("last byte %d\n", arr[len(arr)-1]) // string可以转换为[]byte或[]rune类型
    fmt.Printf("last byte %c\n", arr[len(arr)-1]) // %c以unicode字符进行输出
    fmt.Printf("last rune %d\n", brr[len(brr)-1])
    fmt.Printf("last rune %c\n", brr[len(brr)-1])
    L := len(s1)
    fmt.Printf("string len %d byte array len %d rune
    array len %d\n",L,len(arr),len(brr))
    for _,ele := range sl {
    	fmt.Printf("%c",ele)//按rune进行遍历输出
    }
    fmt.Println()
    for i := 0;i<L;i++ {
    	fmt.Printf("%c",s1[i])//[i]前面应该出现数组或切片,这里自动把string转成了[]byte(而不是[]rune)
    }
    fmt.Println()
    arr[0]=9
    // s1[0]=9·//字符串不能修改
    fmt.Println(utf8.RunecountInstring(s1),len([]rune(s1)))//查看string里有几个rune
}

和 C 语言 []char 的区别

[]char 本质是一个字节数组

特征 C语言 Go语言
内存管理 手动 自动
可变性 可变 不可变
结束符 \0结尾 存储长度
字符集 ASCII/手动UTF-8 默认UTF-8
标准库 <string.h> stringsbytesunicode/utf8
安全性 容易出错 更安全
性能 较高但需谨慎 略低但稳定
相关推荐
lsx2024062 分钟前
C语言中的强制类型转换
开发语言
coderHing[专注前端]5 分钟前
告别 try/catch 地狱:用三元组重新定义 JavaScript 错误处理
开发语言·前端·javascript·react.js·前端框架·ecmascript
开心猴爷19 分钟前
iOS App 性能测试中常被忽略的运行期问题
后端
星辰烈龙24 分钟前
黑马程序员Java基础9
java·开发语言
SHERlocked9337 分钟前
摄像头 RTSP 流视频多路实时监控解决方案实践
c++·后端·音视频开发
@游子42 分钟前
Python类属性与魔术方法全解析
开发语言·python
AutoMQ1 小时前
How does AutoMQ implement a sub-10ms latency Diskless Kafka?
后端·架构
Rover.x1 小时前
Netty基于SpringBoot实现WebSocket
spring boot·后端·websocket
疯狂的程序猴1 小时前
用 HBuilder 上架 iOS 应用时如何管理Bundle ID、证书与描述文件
后端
眠りたいです1 小时前
现代C++:C++11并发支持库
开发语言·c++·多线程·c++11·c++并发支持库