一文详解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
安全性 容易出错 更安全
性能 较高但需谨慎 略低但稳定
相关推荐
Lee川6 小时前
mini-cursor 揭秘:从 Tool 定义到 Agent 循环的完整实现
前端·人工智能·后端
kkeeper~7 小时前
0基础C语言积跬步之深入理解指针(5下)
c语言·开发语言
一直不明飞行7 小时前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
盲敲代码的阿豪7 小时前
Python 入门基础教程(爬虫前置版)
开发语言·爬虫·python
basketball6168 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
互联科技报8 小时前
2026超融合选型:Top5品牌与市场格局解读
开发语言·perl
weixin199701080168 小时前
[特殊字符] 智能数据采集:数字化转型的“数据石油勘探队”(附Python实战源码)
开发语言·python
星浩AI8 小时前
OpenHuman 对比 OpenClaw、Hermes Agent
人工智能·后端·agent
想唱rap9 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
小江的记录本9 小时前
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·mysql·spring·面试·职场和发展