Go 中的 byte、rune 与 string

byte 和 rune

byte 是 uint8 的别名,其字面量是 8 位整数值,byte 切片相比于不可变的 string 方便常用许多。它可以更改每个字节或字符。这对于处理文件内容(无论是文本文件、二进制文件还是来自网络的I/O流)非常有效。byte 切片是一个可变的字节序列

rune 是 int32 的别名,其字面量是 32 位整数值,用来表示 Unicode 字符编码。rune 类似于 byte,不同点在于 rune 每个索引是一个字符而不是一个字节。rune 切片是对字节片的重新分组使得每个索引都是一个字符。

如果你处理的文本文件有很多非 ascii 字符,比如中文文本、数学公式或带有表情符号的文本,使用 rune 是最好的。

rune 也是从字符串中获取子字符串的理想选择。它支持 Unicode 字符,没有数据损坏的风险。

对于 []rune,len()和索引都是基于 rune(int32)的。
当你将 []rune 转换为 string 时,每个 rune 成为字符串中的一个 utf-8 字符。

byte 和 rune 的区别

func main() {
    s := "GÖ"
    sample := "H哈"

    sByte := []byte(s)
    sRune := []rune(s)
    sampleByte := []byte(sample)
    sampleRune := []rune(sample)

    fmt.Printf("%s\nsByte: %d\nsRune: %d\n", s, sByte, sRune)
    fmt.Println("------")
    fmt.Printf("%s\nsampleByte: %d\nsampleRune: %d\n", sample, sampleByte, sampleRune)
}

可以看到rune 中非 ASCII 码字符的 Unicode 编码为 1-3 字节,与 ASCII 码字符的字节数不一定相同。

string

string 是不可变的 byte 切片。因为Go中的源代码使用 utf-8 编码,因此每个字符串也使用utf-8编码,即 string 字面量是 utf-8 编码,以 byte 为单位的。string 中的每个字符实际占用 1-3 个字节,而每个 rune 占 4 个字节。

  • 使用 rune() 可把 byte 为单位的字符转换为 rune 字符,对于 ASCII 字符来说,rune 值和 byte 值相同,而对于 Unicode 编码的字符来说便不同了。
  • 使用 []rune() 将 string 转换 rune 数组。当将字符串转换为 rune 切片时,字符串中的每个 utf-8 字符被转换为一个 rune,从而获得包含字符串 Unicode 编码字符的新切片。
  • 对于 string,len()和索引都是基于 byte(unint8)的
  • 在 Go 中将字符串转换为 rune 切片是一个标准操作,没有数据损坏的风险。
    字符串是处理短字节或字符序列的好方法。每次对字符串进行操作(如查找替换字符串或接受子字符串)时,都会创建一个新字符串。如果字符串非常大,比如文件的内容,效率就会非常低。
    [En]

    Strings are a good way to deal with short bytes or character sequences. Each time you operate on a string, such as finding a replacement string or accepting a substring, a new string is created. If the string is very large, such as the contents of the file, it is very inefficient.

例如我们先看下面程序:

func main() {

    sample := "Hel哈"
    for i := 0; i < len(sample); i++ {
        fmt.Print(sample[i], " ")
    }
    fmt.Println()
    fmt.Printf("%s\t的字节长度: %d\n", sample, len(sample))
    fmt.Printf("哈\t字符的字节长度: %d\n", utf8.RuneLen('哈'))
    fmt.Printf("%s\t的字符长度: %d\n", sample, utf8.RuneCountInString(sample))
}

输出:

72 101 108 229 147 136
Hel哈   的字节长度: 6
哈      字符的字节长度: 3
Hel哈   的字符长度: 4

可以看出字符串的长度(len)和字符串的字符长度(RuneCountInString)是不同的。因为字符串是字节切片,Go 默认 UTF-8,存储非 ASCII 字符时,每个字符则会存储 1-3 个字节。所以想要正确地索引字符串中的字符有以下两种方法:

关于编码的一些方法

utf8.ValidRune(chr) 判断 chr 是否可以编码为合法的utf-8序列。
utf8.RuneLen(chr) 查看字符 chr 的字节长度
utf8.RuneCount() 查看字节数组中按照 rune 单位的字符长度
utf8.RuneCountInString 查看字符串按照 rune 单位的长度

参考资料

Original: https://www.cnblogs.com/vio1etus/p/go-zhong-de-byterune-yu-string.html
Author: vio1etus
Title: Go 中的 byte、rune 与 string

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/514946/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Go内存逃逸分析

    Go的内存逃逸及逃逸分析 Go的内存逃逸 分析内存逃逸之前要搞清楚一件事 我们编写的程序中的 函数和 局部变量默认是存放在栈上的(补充一点堆上存储的数据的指针 是存放在栈上的 因为…

    Go语言 2023年5月25日
    036
  • [原创]Golang一行代码给钉钉群推送消息

    [原创]Golang一行代码给钉钉群推送消息 钉钉本来就是工具,只是boss把你变成了工具. — 麦·卡隆 今天朋友扔给我个某签到脚本,让我做推送功能. 我迅速从吃灰收藏夹里掏出S…

    Go语言 2023年5月25日
    038
  • Go语言之网络编程

    一、网络编程基础 网络基础之TCP/IP协议族 网络编程之socket 二、TCP Socket编程 (一)流程 首先应该了解服务端和客户端的处理流程: 1、服务端处理流程 监听端…

    Go语言 2023年5月29日
    054
  • Sentinel-Go 源码系列(三)滑动时间窗口算法的工程实现

    要说现在工程师最重要的能力,我觉得工程能力要排第一。 就算现在大厂面试经常要手撕算法,也是更偏向考查代码工程实现的能力,之前在群里看到这样的图片,就觉得很离谱。 算法与工程实现 在…

    Go语言 2023年5月25日
    046
  • GO语言HTTP请求案例–httpUtil.go

    package util import (“bytes”“fmt”“io/ioutil”“log…

    Go语言 2023年5月29日
    053
  • Go语言内置函数大全

    https://studygolang.com/articles/1708 Original: https://www.cnblogs.com/answercard/p/12574…

    Go语言 2023年5月29日
    049
  • Go基础知识梳理(四)

    Go基础知识梳理(四) GO的哲学是”不要通过共享内存来通信,而是通过通信来共享内存”,通道是GO通过通信来共享内存的载体。 rumtime包常用方法 ru…

    Go语言 2023年5月25日
    035
  • Excelize 发布 2.6.0 版本,功能强大的 Excel 文档基础库

    Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Mic…

    Go语言 2023年5月25日
    072
  • 【Docker】使用Docker Client和Docker Go SDK为容器分配GPU资源

    深度学习的环境配置通常是一项比较麻烦的工作,尤其是在多个用户共享的服务器上。虽然conda集成了virtualenv这样的工具用来隔离不同的依赖环境,但这种解决方案仍然没办法统一地…

    Go语言 2023年5月25日
    064
  • Golang项目的配置管理——Viper简易入门配置

    Golang项目的配置管理——Viper简易入门配置 What is Viper? From:https://github.com/spf13/viperViper is a co…

    Go语言 2023年5月25日
    043
  • Go语言实现线程安全访问队列

    这个例子用Go语言的包”container/list”实现一个线程安全访问的队列。其中不少细节耐人寻味,做出它则是花费了不少精力,找不到样例啊! Go语言的…

    Go语言 2023年5月29日
    042
  • Golang接口型函数使用技巧

    什么是接口型函数?顾名思义接口函数指的是用函数实现接口,这样在调用的时候就会非常简便,这种方式适用于只有一个函数的接口。 这里以迭代一个map为例,演示这一实现的技巧。 常规接口实…

    Go语言 2023年5月25日
    049
  • 【Go语言】(一)环境搭建与了解VScode工具

    视频链接(p1~p8): golang入门到项目实战 [2022最新Go语言教程,没有废话,纯干货!] 参考链接: 用vscode开发go的时候,安装go包报错:connectex…

    Go语言 2023年5月25日
    055
  • go语言学习笔记

    最近一直在学习go语言,因此打算学习的时候能够记录一下笔记。我这个人之前是从来没有记录笔记的习惯,一直以来都是靠强大的记忆力去把一些要点记住。读书的时候因为一直都是有一个很安静和很…

    Go语言 2023年5月29日
    042
  • go更新腾讯云DNSPod的解析记录

    纯粹练手用的,大家轻喷 获取SecretId,SecretKey 打开腾讯云,登录之后打开 https://console.cloud.tencent.com/cam/capi,然…

    Go语言 2023年5月25日
    051
  • 紫色飞猪的研发之旅–06go自定义状态码

    在实际开发中,需要前后端需要协商状态码,状态码用于后端返前端时使用。在一个团队中,定义的状态码讲道理应该是一致的,项目开始的起始阶段状态码应该是定义了个七七八八的,随着功能的叠加而…

    Go语言 2023年5月25日
    055
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球