ZetCode

Golang Rune 类型

最后修改时间 2025 年 5 月 8 日

本教程讲解如何在 Go 中使用内置的 rune 类型。我们将通过实际的文本处理示例涵盖 Unicode 处理。

Go 中的 rune 类型是 int32 的别名,代表一个 Unicode 码点。它用于处理 UTF-8 编码字符串中的单个字符,UTF-8 是 Go 的默认字符串编码。

在 Go 中,rune 为国际字符提供了良好的支持。与字节不同,rune 可以表示 UTF-8 编码中需要多个字节的字符,例如非 ASCII 字符。

Rune 的基本声明和用法

使用 rune 的最简单方法是将它们声明为字符字面量。此示例演示了基本的 rune 操作和类型转换。
注意:在 Go 中,单引号用于 rune 字面量。

basic_rune.go
package main

import "fmt"

func main() {

    // Declaring rune variables
    var r1 rune = 'A'
    r2 := '€' // Euro symbol
    
    // Printing runes and their types
    fmt.Printf("r1: %c, type: %T\n", r1, r1)
    fmt.Printf("r2: %c, type: %T\n", r2, r2)
    
    // Converting between rune and integer
    codePoint := int(r2)
    fmt.Printf("Euro code point: %d\n", codePoint)
    
    // Converting back to rune
    r3 := rune(codePoint)
    fmt.Printf("Converted back: %c\n", r3)
}

该示例展示了 rune 的声明、使用格式动词进行打印以及 rune 和整数类型之间的转换。%c 格式动词显示字符。

使用 Rune 迭代字符串

Go 中的字符串是 UTF-8 编码的字节序列。使用 range 遍历字符串会遍历 rune,而不是字节。此示例演示了正确的字符串迭代。

string_iteration.go
package main

import "fmt"

func main() {

    s := "Hello, 世界"
    
    // Byte-by-byte iteration
    fmt.Println("Byte iteration:")
    for i := 0; i < len(s); i++ {
        fmt.Printf("%x ", s[i])
    }
    fmt.Println()
    
    // Rune-by-rune iteration
    fmt.Println("Rune iteration:")
    for idx, r := range s {
        fmt.Printf("%d: %c (U+%04X)\n", idx, r, r)
    }
    
    // Counting runes
    fmt.Printf("Length in bytes: %d\n", len(s))
    fmt.Printf("Length in runes: %d\n", len([]rune(s)))
}

range 循环正确处理多字节 UTF-8 字符。字节迭代显示原始字节,而 rune 迭代显示正确的 Unicode 字符。

Rune 操纵和函数

unicode 包提供了用于 rune 分类和转换的函数。此示例演示了常见的 rune 操作。

rune_operations.go
package main

import (
    "fmt"
    "unicode"
)

func main() {

    runes := []rune{'A', 'ä', '3', ' ', '世', '\t'}
    
    for _, r := range runes {
        fmt.Printf("Rune: %c\n", r)
        fmt.Printf("  IsLetter: %t\n", unicode.IsLetter(r))
        fmt.Printf("  IsDigit: %t\n", unicode.IsDigit(r))
        fmt.Printf("  IsSpace: %t\n", unicode.IsSpace(r))
        fmt.Printf("  Lowercase: %c\n", unicode.ToLower(r))
        fmt.Printf("  Uppercase: %c\n", unicode.ToUpper(r))
        fmt.Println()
    }
}

unicode 包的函数使用 rune 来提供字符分类和大小写转换。这对于正确的文本处理至关重要。

从 Rune 构建字符串

Rune 可以转换为字符串,可以单独转换,也可以作为切片转换。此示例展示了从 rune 值构建字符串。

rune_to_string.go
package main

import "fmt"

func main() {

    // Single rune to string
    r := '😊'
    s1 := string(r)
    fmt.Println("Smile:", s1)
    
    // Rune slice to string
    runes := []rune{'H', 'e', 'l', 'l', 'o', ' ', '世', '界'}
    s2 := string(runes)
    fmt.Println("Greeting:", s2)
    
    // Modifying runes in a string
    msg := []rune("Hello World")
    msg[6] = 'G'
    msg[7] = 'o'
    msg[8] = 'l'
    msg[9] = 'a'
    msg[10] = 'ng'
    fmt.Println("Modified:", string(msg))
}

在 Go 中,在 rune 切片和字符串之间进行转换非常高效。这使得通过处理 rune 切片可以轻松地进行字符串操作。

使用 Rune 处理无效 UTF-8

处理外部数据时,可能会出现无效的 UTF-8 序列。此示例演示了如何安全地处理这种情况。

invalid_utf8.go
package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {

    // Contains invalid UTF-8 sequence
    data := []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x80, 0x80, 0xef, 0xbc, 0xa5}
    
    // Safe conversion with utf8.DecodeRune
    for len(data) > 0 {
        r, size := utf8.DecodeRune(data)
        if r == utf8.RuneError {
            fmt.Printf("Invalid UTF-8 sequence: %x\n", data[:size])
        } else {
            fmt.Printf("Valid rune: %c\n", r)
        }
        data = data[size:]
    }
    
    // Checking string validity
    str := string(data)
    if !utf8.ValidString(str) {
        fmt.Println("String contains invalid UTF-8")
    } else {
        fmt.Println("String is valid UTF-8")
    }
}

utf8 包提供了安全处理潜在无效 UTF-8 数据的函数。这对于健壮的文本处理应用程序至关重要。

来源

Go 语言规范

本教程通过 Unicode 文本处理和操作的实际示例,涵盖了 Go 中的 rune 类型。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Golang 教程