深入理解 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语言操作数据库及其常规操作的示例代码
Apr 21 Golang
go原生库的中bytes.Buffer用法
Apr 25 Golang
Golang 正则匹配效率详解
Apr 25 Golang
golang通过递归遍历生成树状结构的操作
Apr 28 Golang
golang 如何用反射reflect操作结构体
Apr 28 Golang
解决golang在import自己的包报错的问题
Apr 29 Golang
解决golang 关于全局变量的坑
May 06 Golang
Golang 获取文件md5校验的方法以及效率对比
May 08 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
一文搞懂Golang 时间和日期相关函数
Dec 06 Golang
Golang Elasticsearches 批量修改查询及发送MQ
Apr 19 Golang
Go语言编译原理之变量捕获
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
搭建Vim为自定义的PHP开发工具的一些技巧
2015/12/11 PHP
PHP MySql增删改查的简单实例
2016/06/21 PHP
CodeIgniter框架验证码类库文件与用法示例
2017/03/18 PHP
对象的类型:本地对象(1)
2006/12/29 Javascript
Javascript Cookie读写删除操作的函数
2010/03/02 Javascript
JavaScript中关于indexOf的使用方法与问题小结
2010/08/05 Javascript
基于jquery实现的鼠标拖拽元素复制并写入效果
2011/08/23 Javascript
javascript 常见功能汇总
2015/06/11 Javascript
理解javascript定时器中的setTimeout与setInterval
2016/02/23 Javascript
jQuery实现的右下角广告窗体跟随效果示例
2016/09/16 Javascript
JS中作用域和变量提升(hoisting)的深入理解
2016/10/31 Javascript
Vue.js中用v-bind绑定class的注意事项
2016/12/13 Javascript
浅析JS抽象工厂模式
2017/12/14 Javascript
vue2.0 自定义 饼状图 (Echarts)组件的方法
2018/03/02 Javascript
基于Vue实现关键词实时搜索高亮显示关键词
2018/07/21 Javascript
详解vuejs2.0 select 动态绑定下拉框支持多选
2019/04/25 Javascript
JS实现的简单tab切换功能完整示例
2019/06/20 Javascript
Jquery cookie插件实现原理代码解析
2020/08/04 jQuery
javascript实现页面的实时时钟显示示例
2020/08/06 Javascript
python统计文本文件内单词数量的方法
2015/05/30 Python
使用Python内置的模块与函数进行不同进制的数的转换
2016/03/12 Python
python实现二维码扫码自动登录淘宝
2016/12/27 Python
python抓取网页中链接的静态图片
2018/01/29 Python
Django进阶之CSRF的解决
2018/08/01 Python
pandas DataFrame行或列的删除方法的实现示例
2019/08/02 Python
python 识别登录验证码图片功能的实现代码(完整代码)
2020/07/03 Python
深入浅析css3 border-image边框图像详解
2015/11/24 HTML / CSS
碧欧泉美国官网:Biotherm美国
2016/08/31 全球购物
浙江文明网签名寄语
2014/01/18 职场文书
班组安全员工作职责
2014/02/01 职场文书
部队党性分析材料
2014/02/16 职场文书
法制宣传标语
2014/06/23 职场文书
学校纪律作风整改措施思想汇报
2014/10/11 职场文书
Apache压力测试工具的安装使用
2021/03/31 Servers
javascript数组includes、reduce的基本使用
2021/07/02 Javascript
Javascript的promise,async和await的区别详解
2022/03/24 Javascript