Golang 中的 String、rune 和 byte

解释

String

Go语言中,string就是只读的采用utf8编码的字节切片(slice) 因此用len函数获取到的长度并不是字符个数,而是字节个数。 for循环遍历输出的也是各个字节。

rune

rune是int32的别名,代表字符的Unicode编码,采用4个字节存储,将string转成rune就意味着任何一个字符都用4个字节来存储其unicode值,这样每次遍历的时候返回的就是unicode值,而不再是字节了,这样就可以解决乱码问题了

byte

bytes操作的对象也是字节切片,与string的不可变不同,byte是可变的,因此string按增量方式构建字符串会导致多次内存分配和复制,使用bytes就不会因而更高效一点

转换方式

String、bytes 相互转换

String to bytes

go 复制代码
func main() {
	str := "Hello, Golang!"
	fmt.Println(string2bytes1(str))
	fmt.Println(string2bytes2(str))
	fmt.Println(string2bytes3(str))
}

func string2bytes1(str string) []byte {
	bs := make([]byte, 0)
	for i := 0; i < len(str); i++ {
		bs = append(bs, str[i])
	}
	return bs
}

func string2bytes2(str string) []byte {
	return []byte(str)
}

func string2bytes3(s string) []byte {
	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
	bh := reflect.SliceHeader{
		Data: sh.Data,
		Len:  sh.Len,
		Cap:  sh.Len,
	}
	return *(*[]byte)(unsafe.Pointer(&bh))
}

前两个方法是非常标准的转换方式,第三种方式使用了 unsafe 和 reflect 处理,是个不安全的做法,而且 StringHeader 在我使用的 1.21 已经废弃了。

bytes to String

go 复制代码
func main() {
	str := "Hello, Golang!"
	bs := string2bytes3(str)
	fmt.Println(bytes2string1(bs))
	fmt.Println(bytes2string2(bs))
}

func bytes2string1(bs []byte) string {
	return string(bs)
}

func bytes2string2(bs []byte) string {
	return *(*string)(unsafe.Pointer(&bs))
}

第一种转换也是一个非常标准的转换方式,第二个方式使用了不安全的做法。

String、rune 相互转换

String to rune

go 复制代码
func main() {
	str := "Hello, 中国!"

	fmt.Println(string2rune1(str))
	fmt.Println(string2rune2(str))
}

func string2rune1(str string) []rune {
	rs := make([]rune, 0)
	for _, r := range str {
		rs = append(rs, r)
	}
	return rs
}

func string2rune2(str string) []rune {
	return []rune(str)
}

这里的 for range 和上面 for index 是不一样的,索引字符串产生字节。For range 循环每次迭代都会解码一个 UTF-8 编码的符文,因此值类型是 rune。

rune to String

go 复制代码
func main() {
	str := "Hello, 中国!"

	rs := string2rune2(str)
	fmt.Println(rune2string1(rs))
}

func rune2string1(rs []rune) string {
	return string(rs)
}

rune、bytes 相互转换

\]rune 和 \[\]byte 的相互转换需要先转成字符串再转换。 ```go func main() { str := "Hello, 中国!" rs := string2rune1(str) bs := string2bytes1(str) convertedBytes := rune2bytes(rs) convertedRunes := bytes2rune(bs) fmt.Println(bs) fmt.Println(convertedBytes) fmt.Println(rs) fmt.Println(convertedRunes) } func rune2bytes(rs []rune) []byte { return []byte(string(rs)) } func bytes2rune(bs []byte) []rune { return []rune(string(bs)) } ``` ## 总结 希望大家通过这篇文章可以巩固自己对这几种类型的理解,以及更方便的对它们进行转换。

相关推荐
virus59451 小时前
悟空CRM mybatis-3.5.3-mapper.dtd错误解决方案
java·开发语言·mybatis
初次见面我叫泰隆2 小时前
Qt——3、常用控件
开发语言·qt·客户端
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
没差c2 小时前
springboot集成flyway
java·spring boot·后端
三水不滴2 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
无小道3 小时前
Qt——QWidget
开发语言·qt
时艰.3 小时前
Java 并发编程之 CAS 与 Atomic 原子操作类
java·开发语言
梵刹古音3 小时前
【C语言】 函数基础与定义
c语言·开发语言·算法
笨蛋不要掉眼泪3 小时前
Spring Boot集成LangChain4j:与大模型对话的极速入门
java·人工智能·后端·spring·langchain
梵刹古音3 小时前
【C语言】 结构化编程与选择结构
c语言·开发语言·嵌入式