教程 > Go 教程 > Go 高级 阅读:1586

Go 语言Rune数据类型的详细介绍

在基础篇 Go 语言字符串详解 一章中,我们介绍过在Go语言中访问字符串的单个字符的方法。在列举的示例中有一个问题,就是如果一个字符占多个字节的话,例如:中文,在访问单个字符的时候就会出现问题。我们看下面的代码

package main

import (  
    "fmt"
)

func printBytes(s string) {  
    fmt.Printf("Bytes: ")
    for i := 0; i < len(s); i++ {
        fmt.Printf("%x ", s[i])
    }
}

func printChars(s string) {  
    fmt.Printf("Characters: ")
    for i := 0; i < len(s); i++ {
        fmt.Printf("%c ", s[i])
    }
}

func main() {  
    name := "Hello World"
    fmt.Printf("String: %s\n", name)
    printChars(name)
    fmt.Printf("\n")
    printBytes(name)
    fmt.Printf("\n\n")
    name = "迹忆客"
    fmt.Printf("String: %s\n", name)
    printChars(name)
    fmt.Printf("\n")
    printBytes(name)
}

运行示例

上述代码执行结果如下

String: Hello World
Characters: H e l l o   W o r l d 
Bytes: 48 65 6c 6c 6f 20 57 6f 72 6c 64 

String: 迹忆客
Characters: è ¿ ¹ å ¿  å ® ¢ 
Bytes: e8 bf b9 e5 bf 86 e5 ae a2

在上面程序中我们试图打印迹忆客的字符。但是出人意料的它打印出了è ¿ ¹ å ¿ å ® ¢ 。为什么会出现这种情况呢,原因就是UTF-8 编码的中文它不是只占一个字节。因此我们试图打印字符,假设每个代码点都是一个字节长,这是错误的。

在 UTF-8 编码中,一个代码点可以占用 1 个以上的字节。

那我们如何解决这个问题呢,那就需要用到 rune 这个万能钥匙了。


Rune

rune 是Go 中的内置类型,它是 int32 的别名。Rune 代表 Go 中的 Unicode 代码点。代码点占用多少字节并不重要,可以用一个符文来表示。

下面让我们修改上面的代码

package main

import (
    "fmt"
)

func printBytes(s string) {
    fmt.Printf("Bytes: ")
    for i := 0; i < len(s); i++ {
        fmt.Printf("%x ", s[i])
    }
}

func printChars(s string) {
    fmt.Printf("Characters: ")
    runes := []rune(s)
    for i := 0; i < len(runes); i++ {
        fmt.Printf("%c ", runes[i])
    }
}

func main() {
    name := "Hello World"
    fmt.Printf("String: %s\n", name)
    printChars(name)
    fmt.Printf("\n")
    printBytes(name)
    fmt.Printf("\n\n")
    name = "迹忆客"
    fmt.Printf("String: %s\n", name)
    printChars(name)
    fmt.Printf("\n")
    printBytes(name)
    fmt.Printf("\n")
}

运行示例

这样上面的代码执行结果如下

String: Hello World
Characters: H e l l o   W o r l d 
Bytes: 48 65 6c 6c 6f 20 57 6f 72 6c 64 

String: 迹忆客
Characters: 迹 忆 客 
Bytes: e8 bf b9 e5 bf 86 e5 ae a2 

上面代码中字符串被转换为一个符文切片。然后我们对它进行循环显示。可以看到,中文的字符已经被正常打印出来了。


使用 for range 循环迭代runes

上面的程序是迭代字符串的各个符文的完美方式。但是使用Go语言的 for range 将更加容易的实现上面的功能。我们看下面的代码

package main

import (  
    "fmt"
)

func charsAndBytePosition(s string) {  
    for index, rune := range s {
        fmt.Printf("%c 从字节 %d 处开始\n", rune, index)
    }
}

func main() {  
    name := "迹忆客"
    charsAndBytePosition(name)
}

运行示例

上面代码执行结果如下

迹 从字节 0 处开始
忆 从字节 3 处开始
客 从字节 6 处开始

从上面的输出中可以很明显的看出,在utf8编码下,每个中文字符占 3 个字节


使用 rune 切片创建字符串

我们直接看示例

package main

import (  
    "fmt"
)

func main() {   
    runeSlice := []rune{0x8ff9, 0x5fc6, 0x5ba2}
    str := string(runeSlice)
    fmt.Println(str)
}

上面代码输出结果如下

迹忆客

在上面的程序中 runeSlice 包含 迹忆客 十六进制字符串的Unicode代码点。

查看笔记

扫码一下
查看教程更方便