深入理解 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语言中的UTF-8实现
Apr 26 Golang
golang日志包logger的用法详解
May 05 Golang
golang 实现时间戳和时间的转化
May 07 Golang
golang 实现并发求和
May 08 Golang
使用GO语言实现Mysql数据库CURD的简单示例
Aug 07 Golang
一文搞懂Golang 时间和日期相关函数
Dec 06 Golang
golang实现浏览器导出excel文件功能
Mar 25 Golang
Go并发4种方法简明讲解
Apr 06 Golang
Go语言的协程上下文的几个方法和用法
Apr 11 Golang
Golang Elasticsearches 批量修改查询及发送MQ
Apr 19 Golang
Golang解析JSON对象
Apr 30 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编程最快明白》第二讲 数字、浮点、布尔型、字符串和数组
2010/11/01 PHP
PHP CodeBase:将时间显示为&quot;刚刚&quot;&quot;n分钟/小时前&quot;的方法详解
2013/06/06 PHP
文件上传之SWFUpload插件(代码)
2015/07/30 PHP
一些常用且实用的原生JavaScript函数
2010/09/08 Javascript
Jquery validation remote 验证的缓存问题解决方法
2014/03/25 Javascript
HTML5游戏引擎LTweenLite实现的超帅动画效果(附demo源码下载)
2016/01/26 Javascript
javascript加减乘除的简单实例
2016/07/12 Javascript
JQuery validate 验证一个单独的表单元素实例
2017/02/17 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
使用Node.js搭建静态资源服务详细教程
2017/08/02 Javascript
React-Router如何进行页面权限管理的方法
2017/12/06 Javascript
vuejs实现递归树型菜单组件
2018/01/13 Javascript
vue自动化表单实例分析
2018/05/06 Javascript
详解处理bootstrap4不支持远程静态框问题
2018/07/20 Javascript
JS/jQuery实现获取时间的方法及常用类完整示例
2019/03/07 jQuery
VUE实时监听元素距离顶部高度的操作
2020/07/29 Javascript
[05:01]3.19DOTA2发布会 我们都是刀塔人
2014/03/25 DOTA
Python的Tornado框架实现异步非阻塞访问数据库的示例
2016/06/30 Python
基于Python中单例模式的几种实现方式及优化详解
2018/01/09 Python
Centos 升级到python3后pip 无法使用的解决方法
2018/06/12 Python
TFRecord文件查看包含的所有Features代码
2020/02/17 Python
Python基于Webhook实现github自动化部署
2020/11/28 Python
英国户外服装、鞋类和设备的领先零售商:Millets
2020/10/12 全球购物
室内设计实习自我鉴定
2013/09/25 职场文书
机电一体化专业应届生求职信
2013/11/27 职场文书
师生聚会感言
2014/01/26 职场文书
营销与策划专业求职信
2014/06/20 职场文书
建筑节能汇报材料
2014/08/22 职场文书
一份关于丢失公司财物的检讨书
2014/09/19 职场文书
2014年数学教师工作总结
2014/12/03 职场文书
2014年村党支部工作总结
2014/12/04 职场文书
中学生自我评价2015
2015/03/03 职场文书
2016读书月活动心得体会
2016/01/14 职场文书
市直属机关2016年主题党日活动总结
2016/04/05 职场文书
详解Python中__new__方法的作用
2022/03/31 Python
shell进度条追踪指令执行时间的场景分析
2022/06/16 Servers