深入理解 Go 中的字符串

目录
  • 字符串的本质
  • 字符串的底层原理

字符串的本质

在编程语言中,字符串发挥着重要的角色。字符串背后的数据结构一般有两种类型:

  • 一种在编译时指定长度,不能修改
  • 一种具有动态的长度,可以修改。

比如:与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 函数
(0)

相关推荐

  • Golang strings包常用字符串操作函数

    目录 func Contains func HasPrefix func HasSuffix func Replace func Split func ToLower func ToUpper func Repeat func Count func Index func Join 在编写代码的时候最常用到的就是字符串了,Golang 中的字符串统一使用 UTF-8 (属于Unicode编码的一种实现方式)进行编码,本篇文章将结合具体实例对常用的字符串操作函数进行介绍. func Contains

  • go语言生成随机数和随机字符串的实现方法

    目录 生成随机数 生成随机字符串 生成随机数 随机数的生成是计算机科学的一个研究领域,同时也是一种艺术.这是因为计算机是纯粹的逻辑机器,所以使用计算机生成随机数异常困难! 你可以用 math/rand 包来生成随机数.开始生成随机数之前首先需要一个种子,种子用于整个过程的初始化,它相当重要.因为如果你每次都用同样的种子初始化,那么就总是会得到相同的随机数序列.这意味着每个人都可以重新生成同一个序列,那这个序列就根本不能再算是随机的了! 我们将用来生成随机数的程序名为 randomNumbers.

  • Golang 字符串与字节数组互转的实现

    目录 一.字符串与字节数组? 二.详细代码 1.字节转字符串 2.字符串转字节数组 3.完整运行测试 总结 一.字符串与字节数组? 字符串是 Go 语言中最常用的基础数据类型之一,本质上是只读的字符型数组,虽然字符串往往都被看做是一个整体,但是实际上字符串是一片连续的内存空间. Go 语言中另外一个类型字节(Byte).在ASCII中,一个英文字母占一个字节的空间,一个中文汉字占两个字节的空间.英文标点占一个字节,中文标点占两个字节.一个Byte数组中的元素对应一个ASCII码. 二.详细代码

  • go语言中五种字符串的拼接方式(小结)

    目录 +拼接方式 sprintf函数 Join函数 buffer.Builderbuffer.WriteString函数 buffer.Builder函数 ps:直接使用运算符 主要结论 +拼接方式 这种方式是我在写golang经常用的方式,go语言用+拼接,php使用.拼接,不过由于golang中的字符串是不可变的类型,因此用 + 连接会产生一个新的字符串对效率有影响. func main() { s1 := "hello" s2 := "word" s3 :=

  • Go语言字符串常见操作的使用汇总

    目录 1. 字节数组 2. 头尾处理 3. 位置索引 4. 替换 5. 统计次数 6. 重复 7. 大小写 8. 去除字符 9. 字符串切片处理 10. 数值处理 1. 字节数组 字节与字符的区别 字节(Byte) 是计量单位,表示数据量多少,是计算机信息技术用于计量存储容量的一种计量单位,通常情况下一字节等于八位 字符(Character) 是计算机中使用的字母.数字.字和符号,比如'A'.'B'.'$'.'&'等 一般在英文状态下一个字母或字符占用一个字节,一个汉字用两个字节表示 通俗点来说

  • GO语言入门学习之基本数据类型字符串

    目录 字符串 字符串转义符 byte和rune类型 修改字符串 类型转换 总结 字符串 Go语言中的字符串以原生数据类型出现. Go 语言里的字符串的内部实现使用UTF-8编码. 字符串的值为双引号(")中的内容,可以在Go语言的源码中直接添加非ASCII码字符 GO语言中字符串是用双引号包裹的 GO语言中单引号包裹的是字符 // 字符串 s := "Hello 中国" // 单独的字母.汉字.符合表示一个字符 c1 := 'h' c2 := '1' c3 := '中' //

  • Go 字符串比较的实现示例

    目录 Compare 和 EqualFold 区别 忽略大小写比较 字符串比较, 可以直接使用 == 进行比较, 也可用用 strings.Compare 比较 go 中字符串比较有三种方式: == 比较 strings.Compare 比较 strings.EquslFold 比较 #### 代码示例 ```go fmt.Println("go"=="go") fmt.Println("GO"=="go") fmt.Prin

  • 深入理解Java中的字符串类型

    1.Java内置对字符串的支持: 所谓的内置支持,即不用像C语言通过char指针实现字符串类型,并且Java的字符串编码是符合Unicode编码标准,这也意味着不用像C++那样通过使用string和wstring类实现与C语言兼容和Unicode标准.Java内部通过String类实现对字符串类型的支持.这意味着:我们可以直接对字符串常量调用和String对象同样的方法: //可以再"abc"上直接调用String对象的所有方法 int length="abc".l

  • 深入理解 Go 中的字符串

    目录 字符串的本质 字符串的底层原理 字符串的本质 在编程语言中,字符串发挥着重要的角色.字符串背后的数据结构一般有两种类型: 一种在编译时指定长度,不能修改 一种具有动态的长度,可以修改. 比如:与Python 中的字符串一样,Go 语言中的字符串不能被修改,只能被访问.在 Python 中,如果改变一个字符串的值会得到如下结果: >>> hi = "Hello" >>> hi 'Hello' >>> hi[0] = 'h' Tr

  • 复习Python中的字符串知识点

    字符串 在 Python 中创建字符串对象非常容易.只要将所需的文本放入一对引号中,就完成了一个新字符串的创建(参见清单 1).如果稍加思考的话,您可能会感到有些困惑.毕竟,有两类可以使用的引号:单引号 (') 和双引号 (").幸运的是,Python 再一次使这种问题迎刃而解.您可以使用任意一类引号来表示 Python 中的字符串,只要引号一致就行.如果字符串是以单引号开始,那么必须以单引号结束,反之亦然.如果不遵循这一规则,则会出现 SyntaxError 异常. 清单 1. 在 Pytho

  • 深入理解MVC中的时间js格式化

    记录下我遇到的一个,MVC中post请求返回一个JSON字符串,其中包含数据库中的时间格式(如:/Date(10000000000)/),不知道怎么处理. 百度的方法都不适用,经自己研究,做成了一个Jquery插件,希望对大家有所帮助. 插件源代码: (function ($) { /格式化JSON返回的日期类型为自己定义的格式:如:yyyy-MM-dd hh:mm:ss dtstr:JSON返回的日期"/Date(10000000000)/" * fmt:自定义的格式,如:yyyy-

  • 深入理解python中的浅拷贝和深拷贝

    在讲什么是深浅拷贝之前,我们先来看这样一个现象: a = ['scolia', 123, [], ] b = a[:] b[2].append(666) print a print b 为什么我只对b进行修改,却影响到了a呢?看过我在之前的文章中就说过:序列中保存的都是内存的引用. 所以,当我们通过b去修改里面的空列表的时候,其实就是修改内存中的同一个对象,所以会影响到a. a = ['scolia', 123, [], ] b = a[:] print id(a), id(a[0]), id(

  • 再谈Python中的字符串与字符编码(推荐)

    本节内容: 1.前言 2.相关概念 3.Python中的默认编码 4.Python2与Python3中对字符串的支持 5.字符编码转换 一.前言 Python中的字符编码是个老生常谈的话题,同行们都写过很多这方面的文章.有的人云亦云,也有的写得很深入.近日看到某知名培训机构的教学视频中再次谈及此问题,讲解的还是不尽人意,所以才想写这篇文字.一方面,梳理一下相关知识,另一方面,希望给其他人些许帮助. Python2的 默认编码 是ASCII,不能识别中文字符,需要显式指定字符编码:Python3的

  • 深入理解C#中的Delegate

    在c#中,event与delegate是两个非常重要的概念.因为在Windows应用程序中,对事件的使用非常频繁,而事件的实现依赖于delegate. 下面是对网上一些比较好的关于delegage的资料的整理,以及自己的一些想法. Delegate是什么? Delegate中文翻译为"委托".Msdn中对Delegate的解释如下: C#中的委托类似于C或C++中的函数指针.使用委托使程序员可以将方法引用封装在委托对象内.然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时

  • 深入理解JS中的substr和substring

    substr 方法 返回一个从指定位置开始的指定长度的子字符串. stringvar.substr(start [, length ]) 参数 stringvar 必选项.要提取子字符串的字符串文字或 String 对象. start 必选项.所需的子字符串的起始位置.字符串中的第一个字符的索引为 0. length 可选项.在返回的子字符串中应包括的字符个数. 说明 如果 length 为 0 或负数,将返回一个空字符串.如果没有指定该参数,则子字符串将延续到 stringvar 的最后. 示

  • AJAX入门之深入理解JavaScript中的函数

    概述 函数是进行模块化程序设计的基础,编写复杂的Ajax应用程序,必须对函数有更深入的了解.JavaScript中的函数不同于其他的语言,每个函数都是作为一个对象被维护和运行的.通过函数对象的性质,可以很方便的将一个函数赋值给一个变量或者将函数作为参数传递.在继续讲述之前,先看一下函数的使用语法: function func1(-){-}var func2=function(-){-};var func3=function func4(-){-};var func5=new Function()

  • 深入学习Java编程中的字符串的进阶使用

    JAVA虽然是在C++基础上发展而来,但却对C++的许多缺陷有所改进,其中一个不得不提的就是字符串,我们知道,随着学习的深入,进入MFC时,当处理字符串或字符时,常会需要通过_T()宏将字符或字符串变成UNICODE型,否则,会在处理中出现BUG,而在JAVA中,字符char或存储在Character类中的字符,不是一个字节,而是2个字节,采用UNICODE,这是为了支持全世界上的所有字符. 字符的序列组成字符串,有两种类型的字符串:一种是创建以后不需要修改的,称为字符串常量,在JAVA中,用S

随机推荐