Golang——rune和byte

embedded/2025/1/15 22:55:31/

本文详细介绍Golang中的两种字符类型rune和byte,介绍他们的区别,编码方式和简单的使用。

在这里插入图片描述

文章目录

      • `byte` 类型
      • `rune` 类型
      • UTF-8 与 Unicode 的关系
      • byte和rune的主要区别
      • Go的默认编码方式
      • 遍历方式
        • 遍历 `byte`
        • 遍历 `rune`
        • 补充
      • 字符还原
        • 从 `byte` 序列还原字符串
        • 从 `rune` 序列还原字符串

在Go语言中,runebyte都是表示单个字符的类型,但它们有一些关键的区别。

byte 类型

byteuint8 的别名,即一个 8 位无符号整数,表示一个字节,范围是 0 到 255。

  • byte 用于表示 UTF-8 编码中的 字节,适合处理字节流和 ASCII 字符。

字符占用字节数:

  • ASCII 字符(0-127)占用 1 字节。
  • 常见的字符,如拉丁字母、标点符号,占用 1 字节。
  • 中文等非 ASCII 字符会占用 3 字节。

byte 表示:字符串 "你",它在 Go 中的 UTF-8 编码是 0xE4, 0xBD, 0xA0(十六进制)。

s := "你"
for i := 0; i < len(s); i++ {fmt.Printf("byte at index %d: %d\n", i, s[i])
}

输出:

byte at index 0: 228
byte at index 1: 189
byte at index 2: 160

rune 类型

runeint32 的别名,即一个 32 位有符号整数,用于表示一个 Unicode 字符。Go中所有字符(包括 ASCII 和 Unicode 字符)都是以 rune 类型表示的,范围是 0 到 0x10FFFF。

  • rune 用于表示 Unicode 字符,它表示字符的 编码点,适合处理字符操作,尤其是涉及 Unicode 字符(如中文、表情符号等)。

rune 表示:

s := "你"
for _, c := range s {fmt.Printf("rune: %c, rune value: %d\n", c, c)
}

输出:

rune: 你, rune value: 20320

这表示 "你" 的 Unicode 编码点(20320,即 0x4F60)被 rune 类型存储。

UTF-8 与 Unicode 的关系

  • Unicode 是字符集,而 UTF-8 是 Unicode 字符集的编码方式之一。Unicode 定义了所有字符的编码点,但它并没有规定字符如何存储和传输。为了实现跨平台和跨语言的兼容,UTF-8 被定义为一种将 Unicode 编码点转换为字节序列的方式。除了 UTF-8 外,还有 UTF-16 和 UTF-32。
  • 联系
    • Unicode 为每个字符分配一个编码点(一个数字)。
    • UTF-8 通过不同长度的字节序列来编码这些 Unicode 编码点,使得它们可以被存储在文件中、传输通过网络、显示在屏幕上等。

byte和rune的主要区别

特性byterune
类型uint8 (8-bit unsigned int)int32 (32-bit signed int)
用途处理 ASCII 或字节数据处理 Unicode 字符
表示范围0 到 2550 到 0x10FFFF
常见应用字节流、ASCII字符Unicode字符(包括多字节字符)
存储大小1 字节4 字节
字符集支持仅支持 ASCII 字符支持所有 Unicode 字符

Go的默认编码方式

Go 字符串默认的编码方式是 UTF-8 。所以默认使用 byte 序列来表示字符串中的每个字符。

具体来说,Go 中的字符串(string 类型)是由 UTF-8 编码的字节序列 组成的。因此:

  • 一个 Go 字符串是由多个字节(byte)组成的,每个字节都是 UTF-8 编码的一个字符。
  • 这些字节遵循 UTF-8 编码,Go 字符串既可以包含 ASCII 字符(这些字符在 UTF-8 中占用 1 个字节),也可以包含多字节的 Unicode 字符(如中文字符,这些字符在 UTF-8 中通常占用 3 个字节)。
s := "a"
fmt.Print("占用字节数:", len(s))
fmt.Printf(";类型:%T  ", s[0])
fmt.Println()
s1 := "你"
fmt.Print("占用字节数:", len(s1))
fmt.Printf(";类型:%T  ", s1[0])

输出:

占用字节数:1;类型:uint8  
占用字节数:3;类型:uint8  

遍历方式

遍历 byte

bytes := []byte(s)可以直接将字符串转为byte,当然也可以遍历:

  • 使用 for i := 0; i < len(s); i++,每次迭代都可以访问字符串中的每个字节。
  • len(s) 返回字符串的 字节数(byte),即字符串中包含的字节总数,而不是字符的数量。对于一个包含多字节字符(如中文字符)的字符串,len(s) 返回的是字符串所占用的字节数。
package mainimport "fmt"func main() {s := "你" // 包含中文字符// 按字节遍历字符串fmt.Println("按字节遍历字符串:")for i := 0; i < len(s); i++ {fmt.Printf("s[%d] = %v (类型: %T)\n", i, s[i], s[i]) // 输出每个字节的值}
}

输出:

按字节遍历字符串:
s[0] = 228 (类型: uint8)
s[1] = 189 (类型: uint8)
s[2] = 160 (类型: uint8)
遍历 rune

runes := []rune(s)可以直接将字符串转为rune,当然也可以遍历:

  • 使用 for _, c := range s 遍历字符串时,Go 会自动将字符串 s 中的每个字符解码成 rune 类型,这样即使字符是多字节的,也能正确处理。

  • range 遍历字符串时,按 字符(rune) 进行迭代。每次迭代返回一个 Unicode 码点(rune) 和该字符在字符串中的索引。对于多字节字符,range 会自动跳过这些字节,按字符来迭代。

package mainimport "fmt"func main() {s := "你"// len(s) 返回字节数fmt.Println("len(s) =", len(s)) // 输出:3,因为“你”是由 3 个字节表示// 使用 range 遍历字符串,按字符(rune)遍历fmt.Println("使用 range 遍历字符串,按字符(rune)遍历:")for i, r := range s {fmt.Printf("i = %d, r = %v (类型: %T)\n", i, r, r)}
}

输出:

len(s) = 3
使用 range 遍历字符串,按字符(rune)遍历:
i = 0, r = 20320 (类型: int32)
补充

for i := range s 的 s[i] 其实也是byte,但是处理中文时候会存在问题。

  • 当你使用for i := range s 处理英文字符串的时候,可能不会有问题,因为英文字符(ASCII 字符)在 UTF-8 编码中是单字节表示的,所以每个字符正好对应一个字节。

  • 但是如果字符串中包含非英文字符(如中文、表情符号等),它们通常会占用多个字节。在这种情况下。使用for i := range s 就会发现问题,range 会按照字符(rune)进行遍历,统计的数量是字符数(rune)【如下只有1个】,而不是字节数(byte)【一个中文,应该是对应3个字节】。

package mainimport "fmt"func main() {s := "你" // 字符串包含中文字符// 使用 range 遍历字符串fmt.Println("使用 range 遍历字符串:")for i := range s {fmt.Printf("s[%d] = %v (类型: %T)\n", i, s[i], s[i]) // 打印每个字节的值}
}

输出:

使用 range 遍历字符串:
s[0] = 228 (类型: uint8)

字符还原

要从 byte 序列或 rune 序列还原回原始字符串,你可以通过以下方式进行操作:

  • byte 序列还原字符串:可以直接使用 string(byteSlice)
  • rune 序列还原字符串:可以直接使用 string(runeSlice)
byte 序列还原字符串
package mainimport "fmt"func main() {s := "你好" // 字符串 "你好"// 将字符串转换成 rune 切片bytes := []byte(s)fmt.Println("bytes:", bytes)// 将 rune 切片转换回字符串s1 := string(bytes)fmt.Println("还原的字符串:", s1)
}
bytes: [228 189 160 229 165 189]
还原的字符串: 你好
rune 序列还原字符串
package mainimport "fmt"func main() {s := "你好" // 字符串 "你好"// 将字符串转换成 rune 切片runes := []rune(s)fmt.Println("runes编码:", runes)// 将 rune 切片转换回字符串s1 := string(runes)fmt.Println("还原的字符串:", s1)
}
runes编码: [20320 22909]
还原的字符串: 你好

http://www.ppmy.cn/embedded/153932.html

相关文章

C# OpenCV机器视觉:转速测量

在一个看似平常却又暗藏神秘能量的日子里&#xff0c;阿杰正在他那充满科技感的实验室里&#xff0c;对着一堆奇奇怪怪的仪器发呆。突然&#xff0c;手机铃声如一道凌厉的剑气划破寂静&#xff0c;原来是工厂的赵厂长打来的紧急电话&#xff1a;“阿杰啊&#xff0c;咱们工厂新…

unity免费资源2025-1-10

https://assetstore.unity.com/packages/3d/characters/humanoids/humans/streetwear-girl-2-8-casual-wear-girls-pack-3-274536 零元购码DAVIDGRETTE2025

特制一个自己的UI库,只用CSS、图标、emoji图 第二版

图&#xff1a; 代码&#xff1a; index.html <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>M…

在 Ubuntu 下通过 Docker 部署 MySQL 服务器

引言 Docker 是一个开源的容器化平台&#xff0c;允许开发者将应用及其依赖打包成一个标准化的单元。MySQL 是一个广泛使用的关系型数据库管理系统&#xff0c;因其高性能、可靠性和易用性&#xff0c;成为许多应用的首选数据库。结合 Docker 和 MySQL&#xff0c;可以轻松地创…

论文阅读:Jailbreak Open-Sourced Large Language Models via Enforced Decoding

1.论文&#xff1a;通过强制解码破解开源大型语言模型【2024ACL】 1.提出问题&#xff1a; 安全对齐真的可以防止那些开源的大型语言模型被误用来成不希望的内容吗? 2.做出假设&#xff1a; 开源模型很容易被误导&#xff0c;在没有大量计算和精细 Prompt 下能够产生恶意内容…

【Vue + Antv X6】可拖拽流程图组件

使用事项&#xff1a; ❗先放个组件上来&#xff0c;使用手册有空会补全 ❗需要下载依赖 “antv/x6”: “^2.18.1”, “antv/x6-plugin-dnd”: “^2.1.1”, 组件&#xff1a; 组件使用&#xff1a; <flowChart :key"flowChartKey" ref"flowChart" lef…

Chromium 中libxml使用c++

Chromium中包含libxml 解析库 读取和写文件包含对应头文件即可。 1、读取xml third_party/libxml/chromium/xml_reader.h #include <map> #include <string>extern "C" { struct _xmlTextReader; }// XmlReader is a wrapper class around libxmls xm…

Ubuntu 24.04蓝牙失效之复活

Thinkpad E450 Ubuntu 24.04 蓝牙突然罢工&#xff0c;设置页面蓝牙无法激活(turn on失效&#xff09;。 网上搜索诸多帖子试了一遍都没有解决&#xff0c;直到拜读到这篇[Solved] Bluetooth down and hciconfig hci0 up timeout / Kernel & Hardware / Arch Linux Forums…