深入理解 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 相关文章推荐
Golang二维切片初始化的实现
Apr 08 Golang
golang正则之命名分组方式
Apr 25 Golang
golang如何去除多余空白字符(含制表符)
Apr 25 Golang
Go使用协程交替打印字符
Apr 29 Golang
Go语言 go程释放操作(退出/销毁)
Apr 30 Golang
Golang之sync.Pool使用详解
May 06 Golang
使用golang编写一个并发工作队列
May 08 Golang
Golang的继承模拟实例
Jun 30 Golang
Golang 遍历二叉树
Apr 19 Golang
Golang并发工具Singleflight
May 06 Golang
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 Golang
GO中sync包自由控制并发示例详解
Aug 05 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
造势之举?韩国总统候选人发布《星际争霸》地图
2017/04/22 星际争霸
PHP register_shutdown_function()函数的使用示例
2015/06/23 PHP
编写PHP脚本来实现WordPress中评论分页的功能
2015/12/10 PHP
PHP+Apache+Mysql环境搭建教程
2016/08/01 PHP
php格式文件打开的四种方法
2018/02/24 PHP
PHP获取当前时间不准确问题解决方案
2020/08/14 PHP
return false,对阻止事件默认动作的一些测试代码
2010/11/17 Javascript
jquery插件制作 手风琴Panel效果实现
2012/08/17 Javascript
JavaScript中this关键词的使用技巧、工作原理以及注意事项
2014/05/20 Javascript
纯js实现仿QQ邮箱弹出确认框
2015/04/29 Javascript
如何使用jquery easyui创建标签组件
2015/11/18 Javascript
基于js中的原型、继承的一些想法
2016/08/10 Javascript
gulp-uglify 与gulp.watch()配合使用时报错(重复压缩问题)
2016/08/24 Javascript
浅谈JavaScript中promise的使用
2017/01/11 Javascript
JS实现AES加密并与PHP互通的方法分析
2017/04/19 Javascript
详谈js对url进行编码和解码(三种方式的区别)
2017/08/16 Javascript
vue获取当前激活路由的方法
2018/03/17 Javascript
NodeJs实现简易WEB上传下载服务器
2019/08/10 NodeJs
javascript(基于jQuery)实现鼠标获取选中的文字示例【测试可用】
2019/10/26 jQuery
js实现div色块拖动录制
2020/01/16 Javascript
vue将文件/图片批量打包下载zip的教程
2020/10/21 Javascript
Python去掉字符串中空格的方法
2014/03/11 Python
python中正则表达式的使用详解
2014/10/17 Python
Python中用max()方法求最大值的介绍
2015/05/15 Python
python中的全局变量用法分析
2015/06/09 Python
python字典值排序并取出前n个key值的方法
2018/10/17 Python
Python Threading 线程/互斥锁/死锁/GIL锁
2019/07/21 Python
python如何将两个txt文件内容合并
2019/10/18 Python
如何基于Python批量下载音乐
2019/11/11 Python
Python新手如何进行闭包时绑定变量操作
2020/05/29 Python
建筑实习自我鉴定
2013/10/18 职场文书
教师实习自我鉴定
2013/12/13 职场文书
离婚答辩状怎么写
2015/05/22 职场文书
2015年基建工作总结范文
2015/05/23 职场文书
催款律师函范文
2015/05/27 职场文书
在Docker容器中部署SQL Server
2022/04/11 Servers