Golang中的字符串迭代与索引

参考

网络工程师的Golang之路 – Go数据类型(字符串) - 知乎 (zhihu.com)

解析Go 中的 rune 类型_Golang_脚本之家 (jb51.net)

1. 问题引出及现象

刚由python转go,刷leetcode每日一题时,按照python的习惯写出来下面这段代码,结果报错:

func minimumSwap(s1 string, s2 string) int {
	var diffA, diffB int
	for idx, c  := range s1{
		if c!=s2[idx]{
			if c=='x'{
				diffA++
			}else{
				diffB++
			}
		}
	}
	if (diffA+diffB) %2 ==1{
		return -1
	}else{
		return diffA/2 + diffB/2 + diffA%2*2
	}
}
 invalid operation: c != s2[idx] (mismatched types rune and byte) (solution.go)

2. rune类型

rune类型是 Go 语言的一种特殊数字类型。

builtin/builtin.go文件中,它的定义:type rune = int32;官方对它的解释是:rune是类型int32的别名,在所有方面都等价于它,用来区分字符值跟整数值。使用单引号定义 ,返回采用 UTF-8 编码的 Unicode 码点。Go 语言通过rune处理中文,支持国际化多语言。

3. go中的字符串

字符串(string)在Go语言和Python中有着一些差别和共同点,具体如下:

  • 根据Go语言官方的定义:*In Go, a string is in effect a read-only slice of bytes.*

意思是Go中的字符串是一组只读的字节切片(slice of bytes,关于切片的概念后文会讲到,这里你可以把它理解为Python中的列表),每个字符串都使用一个或多个字节表示(当字符为 ASCII 码表上的字符时占用 1 个字节,比如英文字母,其它字符根据需要占用 2-4 个字节,比如汉语、日语中的汉字、平假名、片假名等)。

  • Go中的字符串使用的是UTF-8编码,而Python中的字符串则使用的是Unicode编码(Python3)。
  • 综上两点,Go中的纯英文字符串的字节切片长度和它的字母个数完全相等,比如test这个英文单词有4个字母,那么,len(“test”)返回的值也为4(len()函数在Go和Python中的用法一样,都可用来返回字符串的长度,并且返回的值都为整数)。因为英文字母的编码为ASCII,可以用字节表示。 而其他需要用Unicode编码的语言,比如中文字符串,那么它的字节切片长度往往不会等于它的文字个数,比如"测试"这个词语虽然只包含两个汉字,但是len(“测试”)会返回6,因为"测"字和"试"字分别需要用3个字节来表示,总共占用6个字节

而在Python3中,字符串默认就是用Unicode表示,因此在Python3中len(“测试”)会返回2,而不是6。

字符串在底层的表示是由单个字节组成的一个不可修改的字节序列,字节使用UTF-8[1]编码标识Unicode[2]文本。Unicode 文本意味着.go文件内可以包含世界上的任意语言或字符,该文件在任意系统上打开都不会乱码。UTF-8 是 Unicode 的一种实现方式,是一种针对 Unicode 可变长度的字符编码,它定义了字符串具体以何种方式存储在内存中。UFT-8 使用 1 ~ 4 为每个字符编码。

Go 语言把字符分byterune两种类型处理。byte是类型unit8的别名,用于存放占 1 字节的 ASCII 字符,如英文字符,返回的是字符原始字节。rune是类型int32的别名,用于存放多字节字符,如占 3 字节的中文字符,返回的是字符 Unicode 码点值。如下图所示:

img

4. 字符串的迭代与索引

字符串的长度等于其有多少个byte构成,在索引字符串时,返回的是每个字节而非字符。

但是,如果使用range迭代字符串,返回的是字符(rune, 4字节)而非字节。

示例如下:

package main

import (
	"fmt"
	"reflect"
)

func main() {

	str1 := "asd"
	str2 := "你好啊"
	fmt.Println("str1的长度是:", len(str1), "类型是:", reflect.TypeOf(str1), " 值是:", reflect.ValueOf(str1))
	fmt.Println("str2的长度是:", len(str2), "类型是:", reflect.TypeOf(str1), " 值是:", reflect.ValueOf(str1))
	fmt.Println("str1[0]的类型是:", reflect.TypeOf(str1[0]), " 值是:", reflect.ValueOf(str1[0]), " 内容是:", string(str1[0]))
	fmt.Println("str2[0]的类型是:", reflect.TypeOf(str2[0]), " 值是:", reflect.ValueOf(str2[0]), " 内容是:", string(str2[0]))
	for _, v := range str1 {
		fmt.Println("str1的迭代元素是类型是:", reflect.TypeOf(v), " 值是:", reflect.ValueOf(v), " 内容是:", string(v))
	}
	for _, v := range str2 {
		fmt.Println("str2的迭代元素是类型是:", reflect.TypeOf(v), " 值是:", reflect.ValueOf(v), " 内容是:", string(v))
	}
}

ningfeng@ningfeng-OptiPlex-7080:~/go/src/test$ go run main.go
str1的长度是: 3 类型是: string  值是: asd
str2的长度是: 9 类型是: string  值是: asd
str1[0]的类型是: uint8  值是: 97  内容是: a
str2[0]的类型是: uint8  值是: 228  内容是: ä
str1的迭代元素是类型是: int32  值是: 97  内容是: a
str1的迭代元素是类型是: int32  值是: 115  内容是: s
str1的迭代元素是类型是: int32  值是: 100  内容是: d
str2的迭代元素是类型是: int32  值是: 20320  内容是: 你
str2的迭代元素是类型是: int32  值是: 22909  内容是: 好
str2的迭代元素是类型是: int32  值是: 21834  内容是: 啊
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值