问题原因
我们首先了解一下go储存string原理.看下面的测试.
s1 := "abc"
s2 := "我是"
fmt.Printf("%T\n", s1)
fmt.Printf("%T\n", s2)
输出:
string
string
没毛病.
然后,重点:
fmt.Println(len(s1))
输出:3 和预期意一样
可是,当我们fmt.Println(len(s2))
时,输出"6".
这是为什么?因为go使用字节储存str,为了节省内存
计算机中,数据以bin储存(都知道),然后一个ASCII占用1字节,汉字却占3-4,这就造成只占1字节,2字节的字符也必须跟4字节对齐,造成了内存浪费.下面是我自己做的小例子:
假设’a’储存为0001,'b’为0002,'我’为0003 0004 0005,
如果一般存的话,‘ab我’:
0000 0000 0001 0000 0000 0002 0003 0004 0005
8字节.
go中:
0001 0002 0003 0004 0005
5字节
(很显然,随便敲的,)
这也引来了一个问题,也就是今天的重点.
问题本质
由上面的例子看出,我们想访问"a",一般人会用"str[0]",b则是"str[1]"
但是,访问"我",我们天(傻)真(了)无(吧)邪(唧)地用了"str[2]"
明显,乱码.你想啊,下标为0,取出0001
,是a,1,取出0002
,也是b,
但下标2,取出0003
,只是"我"的一部分(怪怪的)
不乱码是啥
但我们如果"str[2:]".正确.
可是,这仅仅局限于需求最后一个汉字,如果要访问"aabb我在cvcv"中的我,咋整?
解决方案
写个函数吧,
func Index(s string, index uint) string {
runes := bytes.Runes([]byte(s))
for i, rune := range runes {
if i == int(index) {
return string(rune)
}
}
return ""
}
网上找了好半天才发现的,具体原理大概好像是用bytes包提供的方法,
记得引入bytes
包.
传参:Index(要提取的字符串->string, 索引->int).
返回单字,如果索引不存在返回空串.