深入理解 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
golang interface判断为空nil的实现代码
Apr 24 Golang
goland 清除所有的默认设置操作
Apr 28 Golang
解决Golang time.Parse和time.Format的时区问题
Apr 29 Golang
go语言中fallthrough的用法说明
May 06 Golang
goland 设置project gopath的操作
May 06 Golang
Goland使用Go Modules创建/管理项目的操作
May 06 Golang
Golang中channel的原理解读(推荐)
Oct 16 Golang
详解Golang如何优雅的终止一个服务
Mar 21 Golang
golang生成vcf通讯录格式文件详情
Mar 25 Golang
golang三种设计模式之简单工厂、方法工厂和抽象工厂
Apr 10 Golang
深入理解 Golang 的字符串
May 04 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
url decode problem 解决方法
2011/12/26 PHP
Yii2中使用join、joinwith多表关联查询
2016/06/30 PHP
PHP中用mysqli面向对象打开连接关闭mysql数据库的方法
2016/11/05 PHP
Javascript 判断函数类型完美解决方案
2009/09/02 Javascript
jQuery之自动完成组件的深入解析
2013/06/19 Javascript
JavaScript中的数学运算介绍
2014/12/29 Javascript
jquery实现表单验证简单实例演示
2015/11/23 Javascript
JavaScript注入漏洞的原理及防范(详解)
2016/12/04 Javascript
详解IWinter 一个路由转控制器的 Nodejs 库
2017/11/15 NodeJs
JavaScript 复制对象与Object.assign方法无法实现深复制
2018/11/02 Javascript
创建与框架无关的JavaScript插件
2020/12/01 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
2021/03/01 Vue.js
[02:40]DOTA2英雄基础教程 先知
2013/11/29 DOTA
[53:52]EG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
基于Python实现定时自动给微信好友发送天气预报
2018/10/25 Python
Windows系统Python直接调用C++ DLL的方法
2019/08/01 Python
浅析Python requests 模块
2020/10/09 Python
python3中确保枚举值代码分析
2020/12/02 Python
利用css3实现的简单的鼠标悬停按钮
2014/11/04 HTML / CSS
英国Zoro工具:手动工具,电动工具和个人防护用品
2016/11/02 全球购物
Veronica Beard官网:在酷、经典和别致之间找到了平衡
2018/01/11 全球购物
Exoticca英国:以最优惠的价格提供豪华异国情调旅行
2018/10/18 全球购物
美国手工艺品市场的领导者:Annie’s
2019/04/04 全球购物
必须要使用游标的SQL语句有那些
2012/05/07 面试题
关于VPN
2012/06/10 面试题
一道Delphi上机题
2012/06/04 面试题
工商管理实习生自我鉴定范文
2013/12/18 职场文书
请假条范文大全
2014/04/10 职场文书
《长城和运河》教学反思
2014/04/14 职场文书
企业安全标语
2014/06/07 职场文书
2014年工程工作总结
2014/11/25 职场文书
2015年科学教研组工作总结
2015/07/22 职场文书
如何书写读后感?(附范文)
2019/07/26 职场文书
Nginx进程管理和重载原理详解
2021/04/22 Servers
MyBatis 动态SQL全面详解
2021/10/05 MySQL
Nginx实现会话保持的两种方式
2022/03/18 Servers