Go string 一清二楚

前言
字符串(string) 作为 go 语言的基本数据类型,在开发中必不可少,我们务必深入学习一下,做到一清二楚。
本文假设读者已经知道切片(slice)的使用,如不了解,可阅读 Go 切片 基本知识点
为了更好的理解后文,推荐先阅读 Unicode 字符集,UTF-8 编码
是什么
In Go, a string is in effect a read-only slice of bytes.
在 go 语言中,字符串实际上是一个只读的字节切片,其数据结构定义如下:
// runtime/string.go
type stringStruct struct {
str unsafe.Pointer // 指向底层字节数组的指针
len int // 字节数组的长度
}
注意:byte 其实是 uint8 的类型别名
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8
怎么用
func main() {
// 使用字符串字面量初始化
var a = "hi,狗"
fmt.Println(a)
// 可以使用下标访问,但不可修改
fmt.Printf("a[0] is %d\n", a[0])
fmt.Printf("a[0:2] is %s\n", a[0:2])
// a[0] = 'a' 编译报错,Cannot assign to a[0]
// 字符串拼接
var b = a + "狗"
fmt.Printf("b is %s\n", b)
// 使用内置 len() 函数获取其长度
fmt.Printf("a's length is: %d\n", len(a))
// 使用 for;len 遍历
for i := 0; i < len(a); i++ {
fmt.Println(i, a[i])
}
// 使用 for;range 遍历
for i, v := range a {
fmt.Println(i, v)
}
}
/* output
hi,狗
a[0] is 104
a[0:2] is hi
b is hi,狗狗
a's length is: 6
0 104
1 105
2 44
3 231
4 139
5 151
0 104
1 105
2 44
3 29399
*/
如果读者在看上面的代码时有疑惑,不用着急,下文将会挨个解读。
只读
字符串常量会在编译期分配到只读段,对应数据地址不可写入,相同的字符串常量不会重复存储
func main() {
var a = "hello"
fmt.Println(a, &a, (*reflect.StringHeader)(unsafe.Pointer(&a)))
a = "world"
fmt.Println(a, &a, (*reflect.StringHeader)(unsafe.Pointer(&a)))
var b = "hello"
fmt.Println(b, &b, (*reflect.StringHeader)(unsafe.Pointer(&b)))
}
/* output
字符串字面量 该变量的内存地址 底层字节切片
hello 0xc0000381f0 &{5033779 5}
world 0xc0000381f0 &{5033844 5}
hello 0xc000038220 &{5033779 5}
*/
可以看到 hello 在底层只存储了一份
for;len 遍历
go 的源代码都是 UTF-8 编码格式的,上例中的”狗“字占用三个字节,即 231 139 151(Unicode Character Table),所以上例的运行结果很清楚。
于此同时,也可以将字符串转化为字节切片
func main() {
var a = "hi,狗"
b := []byte(a)
fmt.Println(b) // [104 105 44 231 139 151]
}
for;range 遍历
The Unicode standard uses the term "code point" to refer to the item represented by a single value.
在 Unicode 标准中,使用术语 code point 来表示由单个值表示的项,通俗点来说,U+72D7(十进制表示为 29399)代表符号 ”狗“
"Code point" is a bit of a mouthful, so Go introduces a shorter term for the concept: rune.
code point 有点拗口,所以在 go 语言中专门有一个术语来代表它,即 rune
注意:rune 其实是 int32 的类型别名
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32
在对字符串类型进行 for;range 遍历时,其实是按照 rune 类型来解码的,所以上例的运行结果也很清晰。
与此同时,也可以将字符串转化为 rune 切片
func main() {
// 使用字符串字面量初始化
var a = "hi,狗"
r := []rune(a)
fmt.Println(r) // [104 105 44 29399]
}
当然我们也可以使用 "unicode/utf8" 标准库,手动实现 for;range 语法糖相同的效果
func main() {
var a = "hi,狗"
for i, w := 0, 0; i < len(a); i += w {
runeValue, width := utf8.DecodeRuneInString(a[i:])
fmt.Printf("%#U starts at byte position %d\n", runeValue, i)
w = width
}
}
/* output
U+0068 'h' starts at byte position 0
U+0069 'i' starts at byte position 1
U+002C ',' starts at byte position 2
U+72D7 '狗' starts at byte position 3
*/
参考
Strings, bytes, runes and characters in Go
Go string 一清二楚的更多相关文章
- 死啃了String源码之后
Java源码之String 说在前面: 为什么看源码: 最好的学习的方式就是模仿,接下来才是创造.而源码就是我们最好的模仿对象,因为写源码的人都不是一般的人,所以用心学习源码,也就可能变成牛逼的人.其 ...
- Go string 详解
前言 字符串(string) 作为 go 语言的基本数据类型,在开发中必不可少,我们务必深入学习一下,做到一清二楚. 本文假设读者已经知道切片(slice)的使用,如不了解,可阅读 Go 切片 基本知 ...
- 透过WinDBG的视角看String
摘要 : 最近在博客园里面看到有人在讨论 C# String的一些特性. 大部分情况下是从CODING的角度来讨论String. 本人觉得非常好奇, 在运行时态, String是如何与这些特性联系上的 ...
- JavaScript String对象
本编主要介绍String 字符串对象. 目录 1. 介绍:阐述 String 对象的说明以及定义方式. 2. 实例属性:介绍 String 对象的实例属性: length. 3. 实例方法:介绍 St ...
- ElasticSearch 5学习(9)——映射和分析(string类型废弃)
在ElasticSearch中,存入文档的内容类似于传统数据每个字段一样,都会有一个指定的属性,为了能够把日期字段处理成日期,把数字字段处理成数字,把字符串字段处理成字符串值,Elasticsearc ...
- [C#] string 与 String,大 S 与小 S 之间没有什么不可言说的秘密
string 与 String,大 S 与小 S 之间没有什么不可言说的秘密 目录 小写 string 与大写 String 声明与初始化 string string 的不可变性 正则 string ...
- js报错: Uncaught RangeError: Invalid string length
在ajax请求后得到的json数据,遍历的时候chrome控制台报这个错误:Uncaught RangeError: Invalid string length,在stackoverflow查找答案时 ...
- c# 字符串连接使用“+”和string.format格式化两种方式
参考文章:http://www.liangshunet.com/ca/201303/218815742.htm 字符串之间的连接常用的两种是:“+”连接.string.format格式化连接.Stri ...
- 【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed
之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码: //将字符串"a"写入流,再拿到流的 ...
随机推荐
- 基于HBuilderX+UniApp+ColorUi+UniCloud 优宝库 开发实战(一)
1. 优宝库介绍 优宝库是基于阿里妈妈.淘宝联盟 淘宝商品Api,前端使用HBuilderX + UniApp + ColorUi,后端采用UniClound 精选淘宝商品进行推荐的App程序.下 ...
- Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Enriching Events(丰富事件信息)
系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...
- 彻底解决小程序无法触发SESSION问题
一.首先找到第一次发起网络请求的地址,将服务器返回set-cookie当全局变量存储起来 wx.request({ ...... success: function(res) { console.lo ...
- ajax异步实现文件分片上传
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- b站视频_下载_去水印_视频转mp4-批量下载神器
b站下载_视频_去水印_转mp4_批量下载的解决办法 以下问题均可解决 b站下载的视频如何保存到本地 b站下载的视频在那个文件夹里 b站下载视频转mp4 b站下载app b站下载在哪 b站下载视频电脑 ...
- 无法获取 vmci 驱动程序版本: 句柄无效。 驱动程序 vmci.sys 版本不正确。请尝试重新安装 VMware Workstation。 打开模块DevicePowerOn电源失败。
1.别打开电源,然后到虚拟机安装文件夹内.2.找到你的虚拟机系统文件中后缀为vmx的文件,右击用记事本或者Notepad++打开.2.搜索找到vmci0.present='TRUE',字段,把true ...
- E2.在shell中正确退出当前表达式
E2.在shell中正确退出当前表达式 优雅退出当前表达式 在shell里面输出复杂的多行表达时,经常由于少输入一个引号,一直无法退出当前的表达式求值,也没有办法终止它,以前只能通过两次Ctrl+C结 ...
- ftp协议服务器与tinyhttp服务demo
https://www.jianshu.com/p/fb9fcb69efc9 ....... https://www.jianshu.com/p/e9a2e0755496 ============== ...
- 使用JWT创建安全的ASP.NET Core Web API
在本文中,你将学习如何在ASP.NET Core Web API中使用JWT身份验证.我将在编写代码时逐步简化.我们将构建两个终结点,一个用于客户登录,另一个用于获取客户订单.这些api将连接到在本地 ...
- Excel 多种粘贴方式
一.粘贴为数值. 这个功能是选择性粘贴中最常用的功能.因为excel主要功能之一就是用来做数据分析,把其他格式粘贴为数据格式才能进行数据运算,把带有公式的计算结果粘贴为数值格式可以使复制后的内容不会变 ...