深入理解 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中切片copy复制和等号复制的区别介绍
Apr 27 Golang
golang http使用踩过的坑与填坑指南
Apr 27 Golang
golang 定时任务方面time.Sleep和time.Tick的优劣对比分析
May 05 Golang
Golang生成Excel文档的方法步骤
Jun 09 Golang
K8s部署发布Golang应用程序的实现方法
Jul 16 Golang
深入理解go缓存库freecache的使用
Feb 15 Golang
Golang 并发下的问题定位及解决方案
Mar 16 Golang
Go语言特点及基本数据类型使用详解
Mar 21 Golang
Go 中的空白标识符下划线
Mar 25 Golang
Golang 1.18 多模块Multi-Module工作区模式的新特性
Apr 11 Golang
golang语言指针操作
Apr 14 Golang
Golang日志包的使用
Apr 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
Mac系统下使用brew搭建PHP(LNMP/LAMP)开发环境
2015/03/03 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
css3实现背景模糊的三种方式
2021/03/09 HTML / CSS
javascript面向对象之Javascript 继承
2010/05/04 Javascript
jquery全选checkBox功能实现代码(取消全选功能)
2013/12/10 Javascript
一张表格告诉你windows.onload()与$(document).ready()的区别
2014/05/16 Javascript
javascript Array 数组常用方法
2015/04/05 Javascript
jQuery实现强制cookie过期方法汇总
2015/05/22 Javascript
jquery实现的蓝色二级导航条效果代码
2015/08/24 Javascript
JS实现左右拖动改变内容显示区域大小的方法
2015/10/13 Javascript
Node.js的Koa框架上手及MySQL操作指南
2016/06/13 Javascript
JS实现密码框的显示密码和隐藏密码功能示例
2016/12/26 Javascript
JS获取本周周一,周末及获取任意时间的周一周末功能示例
2017/02/09 Javascript
前端主流框架vue学习笔记第二篇
2017/07/26 Javascript
js原生代码实现轮播图的实例讲解
2017/07/28 Javascript
Vue学习笔记之表单输入控件绑定
2017/09/05 Javascript
分分钟学会vue中vuex的应用(入门教程)
2017/09/14 Javascript
jquery动态添加以及遍历option并获取特定样式名称的option方法
2018/01/29 jQuery
JS使用cookie保存用户登录信息操作示例
2019/05/30 Javascript
JS表单验证插件之数据与逻辑分离操作实例分析【策略模式】
2020/05/01 Javascript
vue中渲染对象中属性时显示未定义的解决
2020/07/31 Javascript
Python写的英文字符大小写转换代码示例
2015/03/06 Python
详解Django rest_framework实现RESTful API
2018/05/24 Python
python中itertools模块zip_longest函数详解
2018/06/12 Python
Django渲染Markdown文章目录的方法示例
2019/01/02 Python
Python 运行.py文件和交互式运行代码的区别详解
2019/07/02 Python
Python aiohttp百万并发极限测试实例分析
2019/10/26 Python
django实现web接口 python3模拟Post请求方式
2019/11/19 Python
Python的赋值、深拷贝与浅拷贝的区别详解
2020/02/12 Python
matlab、python中矩阵的互相导入导出方式
2020/06/01 Python
Python与C/C++的相互调用案例
2021/03/04 Python
Fairyseason:为个人和批发商提供女装和配件
2017/03/01 全球购物
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
幼儿园中班教学反思
2014/02/10 职场文书
新年寄语大全
2014/04/12 职场文书
安全责任协议书范本
2016/03/23 职场文书