You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中string是引用类型还是值类型?源码与传参疑问

Go语言string类型的本质与传参行为解析

1. string是值类型,但底层基于stringStruct实现

Go里的string是预声明的值类型,但它的底层存储依赖于runtime内部的stringStruct结构,定义大致如下:

type stringStruct struct {
    str unsafe.Pointer // 指向底层字节数组的指针
    len int            // 字符串的长度
}

你在runtime/string.go里看到直接使用string,是因为底层源码不受高层预声明标识符的限制——编译器在编译阶段会自动将高层代码中的string与这个底层结构做映射,相当于string是stringStruct的对外封装。

2. 为什么传参时表现得像值类型?

当你把string变量传入函数时,会完整复制整个stringStruct的值:包括指针和长度字段。这就导致:

  • 形参的stringStruct是一个全新的副本,所以形参与实参的内存地址不同
  • 虽然副本的指针指向同一个底层字节数组,但Go规定string是不可变类型——你无法直接修改底层字节数组的内容(强行通过unsafe包修改会触发未定义行为),而修改形参本身(比如重新赋值s = "new")只是改变了副本的指针和长度,完全不会影响实参的stringStruct

这就是为什么string传参后修改形参不会影响实参,表现完全符合值类型的特征。

3. 关于“string是引用类型”的误区

有些文章称string是引用类型,其实是混淆了“底层包含指针”和“引用类型”的概念。Go里的引用类型(slice、map、channel)的核心特征是:修改类型的内容会影响共享的底层数据,但string因为不可变性,即使底层有指针,也无法通过它修改底层数据;加上传参是复制整个结构,所以它不属于Go官方定义的引用类型范畴。

4. string的行为定义在哪里?

string的核心行为由两部分实现:

  • 编译期处理:比如len(s)、字符串索引、字面量赋值等操作,编译器会直接翻译成对stringStruct字段的访问,不需要调用函数
  • runtime包实现:复杂操作比如字符串拼接、转换(如[]byte(s))、比较等,都在runtime/string.go中实现对应的函数(比如concatstrings、stringtoslicebyte),这些函数会直接操作stringStruct的指针和长度字段

内容的提问来源于stack exchange,提问作者afraid.jpg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 10:41:32