文章目录
- Go语言字符串的本质
 - 和其他类型的转换(内存结构的变化)
 - [和 C 语言 `[]char` 的区别](#和 C 语言 
[]char的区别) 
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> | 
strings、bytes、unicode/utf8 | 
| 安全性 | 容易出错 | 更安全 | 
| 性能 | 较高但需谨慎 | 略低但稳定 |