深入理解 Golang 的字符串


Posted in Golang onMay 04, 2022

字符串的本质

在编程语言中,字符串发挥着重要的角色。字符串背后的数据结构一般有两种类型:

  • 一种在编译时指定长度,不能修改
  • 一种具有动态的长度,可以修改。

比如:与Python 中的字符串一样,Go 语言中的字符串不能被修改,只能被访问。
在 Python 中,如果改变一个字符串的值会得到如下结果:

>>> hi = "Hello"
>>> hi
'Hello'
>>> hi[0] = 'h'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>>

同理,在 Go 中也一样:

package main
import "fmt"
func main() {
var hello = "Hello"
hello[1] = 'h'
fmt.Println(hello)
}
// # command-line-arguments
// string_in_go/main.go:8:11: cannot assign to hello[1] (strings are immutable)

字符串的终止方式有两种:

  • 一种是 C 语言的隐式声明,以字符 “\0” 作为终止符
  • 一种是 Go 语言的显式声明

Go 语言的 string 的表示结构如下:

type StringHeader struct {
Data uintptr // Data 指向底层的字符数组
Len int // Len 用来表示字符串的长度
}

字符串的本质上是一串字符数组,每个字符都在存储时对应了一个或多个整数。用这些整数来表示字符,比如打印 hello 的字节数组如下:

package main
import "fmt"
func main() {
var hello = "Hello"
for i := 0; i < len(hello); i++ {
fmt.Printf("%x ", hello[i])
}
}
// Output: 48 65 6c 6c 6f

字符串的底层原理

字符串有特殊标识,有两种声明方式:

var s1 string = `hello world`
var s2 string = "hello world"

字符串常量在词法解析阶段最终会被标记为 StringLit 类型的 Token 并被传递到编译的下一个阶段。
在语法分析阶段,采取递归下降的方式读取 UTF-8 字符,单撇号或双引号是字符串的标识。

分析的逻辑位于  syntax/scanner.go 文件中:

func (s *scanner) stdString() {
ok := true
s.nextch()
for {
if s.ch == '"' {
s.nextch()
break
}
if s.ch == '\\' {
s.nextch()
if !s.escape('"') {
ok = false
}
continue
}
if s.ch == '\n' {
s.errorf("newline in string")
ok = false
break
}
if s.ch < 0 {
s.errorAtf(0, "string not terminated")
ok = false
break
}
s.nextch()
}
s.setLit(StringLit, ok)
}
func (s *scanner) rawString() {
ok := true
s.nextch()
for {
if s.ch == '`' {
s.nextch()
break
}
if s.ch < 0 {
s.errorAtf(0, "string not terminated")
ok = false
break
}
s.nextch()
}
// We leave CRs in the string since they are part of the
// literal (even though they are not part of the literal
// value).
s.setLit(StringLit, ok)
}

从上面的代码可以看到,Go 中有两种字符串的检查:一种是标准字符串以双引号定义 "",如 "Hello,World", 还有一种是原始字符串,用 \\ 定义的, 因此针对两种字符串有两种语法分析函数:

  • 如果是单撇号,则调用 rawString 函数
  • 如果是双引号,则调用 stdString 函数
Golang 相关文章推荐
go:垃圾回收GC触发条件详解
Apr 24 Golang
go 原生http web 服务跨域restful api的写法介绍
Apr 27 Golang
解决Golang中goroutine执行速度的问题
May 02 Golang
golang elasticsearch Client的使用详解
May 05 Golang
Golang实现AES对称加密的过程详解
May 20 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
Go语言实现一个简单的并发聊天室的项目实战
Mar 18 Golang
Go并发4种方法简明讲解
Apr 06 Golang
golang使用map实现去除重复数组
Apr 14 Golang
Golang获取List列表元素的四种方式
Apr 20 Golang
Golang并发工具Singleflight
May 06 Golang
Go语言入门exec的基本使用
May 20 Golang
Golang入门之计时器
May 04 #Golang
Golang 入门 之url 包
May 04 #Golang
Golang解析JSON对象
Apr 30 #Golang
Golang 并发编程 SingleFlight模式
Golang 实现 WebSockets 之创建 WebSockets
Apr 24 #Golang
Golang 实现WebSockets
Golang ort 中的sortInts 方法
Apr 24 #Golang
You might like
常用的php对象类型判断
2008/08/27 PHP
修改php.ini不生效问题解决方法(上传大于8M的文件)
2013/06/14 PHP
php selectradio和checkbox默认选择的实现方法详解
2013/06/29 PHP
PHP面向对象程序设计之类常量用法实例
2014/08/20 PHP
直接生成打开窗口代码,不必下载
2008/05/14 Javascript
JS定时器实例详细分析
2013/10/11 Javascript
jquery高级编程的最佳实践详解
2014/03/23 Javascript
单击和双击事件的冲突处理示例代码
2014/04/03 Javascript
JavaScript及jquey实现多个数组的合并操作
2014/09/06 Javascript
javascript中indexOf技术详解
2015/05/07 Javascript
JS模拟酷狗音乐播放器收缩折叠关闭效果代码
2015/10/29 Javascript
JS中JSON对象和String之间的互转及处理技巧
2016/04/06 Javascript
ES6新特性七:数组的扩充详解
2017/04/21 Javascript
浅谈Vue.js中的v-on(事件处理)
2017/09/05 Javascript
Vue的路由动态重定向和导航守卫实例
2018/03/17 Javascript
Vue配合iView实现省市二级联动的示例代码
2018/07/27 Javascript
在小程序/mpvue中使用flyio发起网络请求的方法
2018/09/13 Javascript
elementUI多选框反选的实现代码
2019/04/03 Javascript
一百行JS代码实现一个校验工具
2019/04/30 Javascript
微信小程序常用的3种提示弹窗实现详解
2019/09/19 Javascript
深入了解JavaScript词法作用域
2020/07/29 Javascript
[01:41]DOTA2超级联赛专访YYF 称一辈子难忘TI2
2013/05/28 DOTA
编写Python脚本抓取网络小说来制作自己的阅读器
2015/08/20 Python
python3利用Dlib19.7实现人脸68个特征点标定
2018/02/26 Python
Python实现绘制双柱状图并显示数值功能示例
2018/06/23 Python
Pandas 数据处理,数据清洗详解
2018/07/10 Python
python3 实现的对象与json相互转换操作示例
2019/08/17 Python
PyCharm更改字体和界面样式的方法步骤
2019/09/27 Python
pip install python 快速安装模块的教程图解
2019/10/08 Python
Mamas & Papas沙特阿拉伯:英国最受欢迎的婴儿品牌
2017/11/20 全球购物
SmartBuyGlasses意大利:购买太阳镜、眼镜和隐形眼镜
2018/11/20 全球购物
教师岗位聘任书范文
2014/03/29 职场文书
化工生产实习心得体会
2016/01/22 职场文书
2019班干部竞选演讲稿范本!
2019/07/08 职场文书
Vue项目打包、合并及压缩优化网页响应速度
2021/07/07 Vue.js
java调用Restful接口的三种方法
2021/08/23 Java/Android