[转]全面认识golang string
作者:@apocelipes
本文为作者原创,转载请注明出处:https://www.cnblogs.com/apocelipes/p/9798413.html
string我们每天都在使用,可是对于string的细节问题你真的了解吗?
今天我们先以一个问题开篇。
你能猜到下面代码的输出吗?
package main import (
"fmt"
) func main() {
s := "测试"
fmt.Println(s)
fmt.Println(len(s))
fmt.Println(s[0])
for _, v := range s {
fmt.Println(v)
}
}
谜底揭晓:

是不是觉得很奇怪?明明是2个汉字,为啥长度是6?为啥s[0]是个数字,又为啥长度是6却只循环了两次,而且输出的也是数字?
别急,我们一个个地说明。
string的真实长度
要知道string的长度,首先要知道string里到底存了什么,我们看下官方的文档:
type string string
string is the set of all strings of 8-bit bytes, conventionally but not
necessarily representing UTF-8-encoded text. A string may be empty, but not
nil. Values of string type are immutable.
是的,没看错,在string里存储的是字符按照utf8编码后的“8-bit bytes”二进制数据,再说得明确点,就是我们熟悉的byte类型:
type 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.
我们都知道,utf8在表示中文时需要2个字节以上的空间,这里我们一个汉字是3字节,所以总长度就是我们直接用len得到的6。
从string中索引到的值
从string里使用索引值得到的数据也是byte类型的,所以才会输出数字,最好的证据在于此(最后还会有证明代码),还记得byte的文档吗:
type byte = uint8
如果看不懂,没关系,这是golang的type alias语法,相当于给某个类型起了个别名,而不是创建了新类型,所以byte就是uint8。
所以,输出uint8类型的数据,那么自然会看到数字。
range string时发生了什么?
那么range的情况呢,长度是,为什么只循环两次?
首先我们可以排除byte了,uint8怎么可能会有20000的值。
然后我们来看一下官方文档,其中有这么一段:
For strings, the range does more work for you, breaking out individual
Unicode code points by parsing the UTF-8. Erroneous encodings consume
one byte and produce the replacement rune U+FFFD.
(The name (with associated builtin type) rune is Go terminology for a single Unicode code point. See the language specification for details.) The loop
有点长,大致意思就是range会把string里的byte重新转换成utf8字符,对于错误的编码就用一字节的占位符替代,这下清楚了,range实际上和如下代码基本等价:
for _, v := range []rune(s)
我们是字符串正好是2个utf8字符,所以循环输出两次。我们再看看看看rune的文档:
type 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.
rune是int32的别名,它的值是Unicode码点,所以当我们println时就看到了数字。
代码验证
虽然没什么必要,但我们还是可以通过代码不算太严谨地验证一下我们得到的结论,想获取变量的类型,使用reflect.TypeOf即可(无法获取别名,所以“不严谨”):
package main import (
"fmt"
"reflect"
) func main() {
s := "测试"
fmt.Println("s type:", reflect.TypeOf(s))
fmt.Println("s[index] type:", reflect.TypeOf(s[0]))
for _, v := range s {
fmt.Println("range value type:", reflect.TypeOf(v))
}
}

与我们预想的一样,uint8是byte,int32是rune,虽然TypeOf无法输出类型别名,但我们还是可以粗略判断出它的类型名称。
[转]全面认识golang string的更多相关文章
- golang string和[]byte的对比
golang string和[]byte的对比 为啥string和[]byte类型转换需要一定的代价?为啥内置函数copy会有一种特殊情况copy(dst []byte, src string) in ...
- 全面认识golang string
string我们每天都在使用,可是对于string的细节问题你真的了解吗? 今天我们先以一个问题开篇. 你能猜到下面代码的输出吗? package main import ( "fmt&qu ...
- golang string转json的一些坑
先带来点冷知识,不知道大家知不知道,反正我刚知道... 大佬们都知道怎么在string中给string类型赋值带双引号的字符串,没错就是用反斜杠,如下: msg := "{\"na ...
- golang string int int64转换
#string到int int,err:=strconv.Atoi(string) #string到int64 int64, err := strconv.ParseInt(string, 10, 6 ...
- golang string、int、int64 float 互相转换
#string到int int,err := strconv.Atoi(string) #string到int64 int64, err := strconv.ParseInt(string, 10, ...
- Golang中string和[]byte的对比
golang string和[]byte的对比 为啥string和[]byte类型转换需要一定的代价? 为啥内置函数copy会有一种特殊情况copy(dst []byte, src string) i ...
- GO开发[五]:golang结构体struct
Go结构体struct Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性 ...
- golang cgo 使用总结
原文地址 CGO 提供了 golang 和 C 语言相互调用的机制.某些第三方库可能只有 C/C++ 的实现,完全用纯 golang 的实现可能工程浩大,这时候 CGO 就派上用场了.可以通 CGO ...
- golang 字符串与整数, 布尔转换 strconv
strconv 是golang对于字符串和基本数据类型之间的转换字符串转整数testStr := "1000" testInt, err := strconv.Atoi(testS ...
随机推荐
- 关于VS2015 发布.net mvc 网站失败的问题
问题:VS生成成功,发布失败,在“正在连接到***文件夹”处就不能继续了.. 项目开发告一段落,准备部署到服务器上进行最后测试,但是始终发布失败 生成成功,发布失败,没有任何提示信息 一开始以为是文 ...
- tensorflow模型量化实例
1,概述 模型量化应该是现在最容易实现的模型压缩技术,而且也基本上是在移动端部署的模型的毕竟之路.模型量化基本可以分为两种:post training quantizated和quantization ...
- Git的一些概念(二)
一.Git的结构 二.Git和代码托管中心 代码托管中心的任务:维护远程库 1. 局域网内 GitLab 服务器 -- 可以自己搭建 2. 外部环境 GitHub 码云 三.本地库和远程库 1. 团队 ...
- 通过Socket实现TCP编程(十二)
原文链接:https://www.cnblogs.com/hysum/p/7531529.html Socket通信 : TCP协议是面向对象连接.可靠的.有序的,以字节流的方式发送数据. 基于TCP ...
- Django2.2 Vue 前后端分离 无法访问Cookie
个人验证后可用配置如下: 环境: - Django 2.2 - djangorestframework 3.9 - django-cors-headers 2.5.3 INSTALLED_APPS = ...
- [RN] React Native FlatList 选中后 状态没有立即发生改变,而在下一次生效的问题
React Native FlatList 选中后 状态没有立即发生改变,而在下一次生效的问题 解决关键: 给 FlatList 添加 extraData={this.state} 非常关键,如果不设 ...
- requests--传递参数
传递参数 传递URL参数 data = {'city': '北京'} # 参数有中文如果发送不了,必须要编码 city = parse.urlencode(data).encode('utf-8') ...
- 容错框架之Hystrix小记
微服务框架下,一个服务依赖于很多服务.在高并发访问下,系统所依赖的服务的稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,服务脱机等,一个被调用服务出问题可 ...
- VUE的$refs和$el的使用
ref 被用来给元素或子组件注册引用信息 ref 有三种用法: 1.ref 加在普通的元素上,用this.$refs.(ref值) 获取到的是dom元素 2.ref 加在子组件上,用this.$ref ...
- Linux 分区管理器
下面的列表没有特定的排名顺序.大多数分区工具应该存在于 Linux 发行版的仓库中. GParted 这可能是 Linux 发行版中最流行的基于 GUI 的分区管理器.你可能已在某些发行版中预装它.如 ...