一文详解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
安全性 容易出错 更安全
性能 较高但需谨慎 略低但稳定
相关推荐
Pa2sw0rd丶几秒前
Fastjson 反序列化漏洞深度解析:从原理到实战防护
java·后端·安全
q***64974 分钟前
SpringSecurity踢出指定用户
android·前端·后端
Coding_Doggy7 分钟前
链盾shieldchiain | 团队功能、邀请成员、权限修改、移除成员、SpringSecurity、RBAC权限控制
java·开发语言·数据库
q***76667 分钟前
SpringSecurity 实现token 认证
android·前端·后端
川白11 分钟前
为防在家摸鱼,用计网知识实践屏蔽B站!
后端
吃果冻不吐果冻皮17 分钟前
DeepSeek 视觉语言大模型技术演进(从DeepSeek VL/VL2到DeepSeek OCR)
后端
申阳17 分钟前
Day 15:01. 基于 Tauri 2.0 开发后台管理系统-Tauri 2.0 初探
前端·后端·程序员
武子康20 分钟前
大数据-164 Apache Kylin Cuboid 剪枝实战:Derived 维度与膨胀率控制
大数据·后端·apache kylin
Lear22 分钟前
Java中byte[]转MultipartFile
后端
程序员小假25 分钟前
有了解过 SpringBoot 的参数配置吗?
java·后端