经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
全面了解golang string
来源:cnblogs  作者:apocelipes  时间:2018/10/17 9:04:41  对本文有异议

string我们每天都在使用,可是对于string的细节问题你真的了解吗?

今天我们先以一个问题开篇。

你能猜到下面代码的输出吗?

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. s := "测试"
  7. fmt.Println(s)
  8. fmt.Println(len(s))
  9. fmt.Println(s[0])
  10. for _, v := range s {
  11. fmt.Println(v)
  12. }
  13. }

谜底揭晓:

是不是觉得很奇怪?明明是2个汉字,为啥长度是6?为啥s[0]是个数字,又为啥长度是6却只循环了两次,而且输出的也是数字?

别急,我们一个个地说明。

 

长度

要知道string的长度,首先要知道string里到底存了什么,我们看下官方的文档:

  1. type string string
  2. string is the set of all strings of 8-bit bytes, conventionally but not
  3. necessarily representing UTF-8-encoded text. A string may be empty, but not
  4. nil. Values of string type are immutable.

是的,没看错,在string里存储的是字符按照utf8编码后的“8-bit bytes”二进制数据,再说得明确点,就是我们熟悉的byte类型:

  1. type byte = uint8
  2. byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
  3. used, by convention, to distinguish byte values from 8-bit unsigned integer
  4. values.

我们都知道,utf8在表示中文时需要2个字节以上的空间,这里我们一个汉字是3字节,所以总长度就是我们直接用len得到的6。

 

从string中索引到的值

从string里使用索引值得到的数据也是byte类型的,所以才会输出数字,最好的证据在于此(最后还会有证明代码),还记得byte的文档吗:

  1. type byte = uint8

如果看不懂,没关系,这是golang的type alias语法,相当于给某个类型起了个别名,而不是创建了新类型,所以byte就是uint8。

所以,输出uint8类型的数据,那么自然会看到数字。

 

range string时得到的值

那么range的情况呢,长度是,为什么只循环两次?

首先我们可以排除byte了,uint8怎么可能会有20000的值。

首先我们来看一下官方文档,其中有这么一段:

  1. For strings, the range does more work for you, breaking out individual
  2. Unicode code points by parsing the UTF-8. Erroneous encodings consume
  3. one byte and produce the replacement rune U+FFFD.
  4. (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实际上和如下代码基本等价:

  1. for _, v := range []rune(s)

我们是字符串正好是2个utf8字符,所以循环输出两次。我们再看看看看rune的文档:

  1. type rune = int32
  2. rune is an alias for int32 and is equivalent to int32 in all ways. It is
  3. used, by convention, to distinguish character values from integer values.

rune是int32的别名,它的值是Unicode码点,所以当我们println时就看到了数字。

 

代码验证

虽然没什么必要,但我们还是可以通过代码不算太严谨地验证一下我们得到的结论,想获取变量的类型,使用reflect.TypeOf即可(无法获取别名,所以“不严谨”):

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. s := "测试"
  8. fmt.Println("s type:", reflect.TypeOf(s))
  9. fmt.Println("s[index] type:", reflect.TypeOf(s[0]))
  10. for _, v := range s {
  11. fmt.Println("range value type:", reflect.TypeOf(v))
  12. }
  13. }

与我们预想的一样,uint8是byte,int32是rune,虽然TypeOf无法输出类型别名,但我们还是可以粗略判断出它的类型名称。

 

通过这篇文章,我们已经对string类型有了全面的认知。

如有错误欢迎指正!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号