基础
1 .字符串是一个不可改变的字节序列,一系列8位字节的集合
2 .字符串可以包含任何的数据,包括byte和0.
3 .字符串是一种值类型,且值不能改变,创建某个文本之后无法再次改变这个文本的内容
4 .字符串是字节的定长数组
5 .传统过的字符串是由字符组成的,go的字符串是单个字节链接起来的数组
6 .字节使用utf编码的Unicode文本
7 .字符串底层就是Byte数组
8 .[]byte方法和[]rune方法就是将字符串转化成对应类型的slice
9 .字符串常量一般使用单引号括起来的单个字符
10 .在golang中,字符,字符串中打印单个字符的本质就是一个整数,是改字符对应的utf-8编码的码值
11 .可以给某个变量赋一个数字,然后格式化初始时%c,会输出对应数字的unicode字符
12 .因为字符的本质时一个整数,所以字符类型是可以计算的。
13 .字符-计算机:字符-对应码值-二进制
14 .计算机-字符:二进制-码值-字符
type stringStruct struct {
str unsafe.Pointer
len int
}
//str:指向某个数组的指针
字符串类型
1 .解释型字符串
1 .使用双引号包起来,其中的转义字符串将被替换
2 .\n
3 .\r
4 .\t
5 .\u
6 .\\
2 .非解释字符串
1 .使用``包起来.支持换行
2 .
字符串基于UTF8编码
1 .通过rune类型,可以方便的对每个UTF8字符进行访问
2 .
s:="123 飞机"
b:=[]byte(s)
for _,v:=range b{
fmt.Printf("%v \n",v)
}
fmt.Println(string(b))
for _,v:=range s{
fmt.Printf("%c \n",v)
}
for _,v:=range []rune(s){
fmt.Printf("%c \n",v)
}
字符串的长度
1 .len:计算切片,字符串,通道的长度。返回值的类型为 int,表示字符串的 ASCII 字符个数或字节长度.ASCII 字符串长度使用 len() 函数。
2 .统计utf8字符串的长度.Unicode 字符串长度使用 utf8.RuneCountInString() 函数
字符串遍历
1 .不管是asicc还是utf8都使用for range就可以了,不会出现乱码。唯一缺点就是中文下标不准确,不是递增的
2 .
str:="love 哈哈"
for _,v:=range str{
fmt.Printf("%c\n",v)
// fmt.Println(v)
}
//怎么都会输出正确的
for i:=0;i<len(str);i++{
fmt.Printf("%c\n",str[i])
// fmt.Println(str[i])
}
3 .len遍历:按照字节进行遍历,如果有非英文字节,就会出现乱码
4 .切片遍历:先将字符串转为[]rune切片,然后按照常规方式进行遍历
func main(){
str:="hello 北京"
s:=[]rune(str)
fmt.Println(s)
for i:=0;i<len(s);i++{
fmt.Printf("str[%d]=%c",i,s[i])
}
}
//步长是按照1递增的,没有进行跳跃
字符串截取
1 .索引的起使位置可以通过切片偏移制作
s:="死神来了, 阿斯蒂死神啦啦啦"
index:=strings.Index(s,",")
// 返回第一个”,“号的索引
fmt.Println(index)
pos:=strings.Index(s[index:],"死神")
//这样直接切割是有问题的
// 接入第一个”,“号之后的字符串,寻找”死神"在新字符串的位置
fmt.Println(pos)
fmt.Println(s[index+pos:])
// 把两个位置相加,取出最后想要的串
fmt.Println(b)
// byte表示一个字节
fmt.Println(c)
// rune表示四个字节
fmt.Println(s[:1])
fmt.Println(string(b[:1]))
fmt.Println(string(c[:1]))
修改字符串
1 .go无法直接修改每一个字符元素,只能重新构造新的字符串赋值给原来的字符串变量实现
2 .修改字符串的时候,可以将字符串转换为[]byte进行修改
3 .[]byte和string可以通过强制类型互相转换
s1:="helllo"
s2:=[]byte(s1)
//将字符串转为byte切片
for i:=3;i<len(s2);i++{
s2[i]=' '
}
//3-len之间的元素使用空格替换
fmt.Println(string(s2))
// 利用string方法将[]byte转为字符串,重新创造一个字符串
字符串拼接
1 .+号:每次加号都会产生一个新的字符串,导致很多临时的,无用的字符串,会给垃圾回收带来很大的压力
2 .高速缓冲实现
var stringBuilder bytes.Buffer
// 声明一个字节缓冲
stringBuilder.WriteString("李")
stringBuilder.WriteString("巴")
// 向里面添加数据
fmt.Println(stringBuilder.String())
// 将缓冲以字符串形式输出
3 .fmt.Sprintf()函数
func main(){
x := "hello"
for _, y := range x {
x=fmt.Sprintf("%s %s",x,string(y))
}
fmt.Println(x)
}
1 .格式化样式:字符串形式,如s%,s%
2 .参数列表:多个参数以逗号隔开,个数必须和格式化样式中的个数一一对应
3 .功能:将参数列表中的多个参数以格式化的形式输出
4 .缺点:虽然不会产生临时字符串,但是内部逻辑比较复杂,而且有很多额外的判断,性能也一般
4 .strings.join()函数
func main(){
str:=[]string{"a","b","c","d"}
s:=strings.Join(str,"-")
//用-来连接
fmt.Println(s)
}
1 .Join会根据字符串数组的内容,计算出一个拼接后的长度,然后申请对应大小的内存,依次将该字符串填入。
2 .该种方式在已有一个数组的前提下,可以提高程序的执行效率,但实际上,原先内存中并没有为拼接之后的字符串所创建好的数组,所以本质上创建这个数据的代价并不小
5 .连接性能比较
1 .较少字符串使用+号
2 .如果拼接的不仅仅是字符串,还有数字之类的其他需求,使用fmt.Sprintf函数
3 .在已有字符串数组的情况下,使用strings.Join
4 .在性能要求高的场景下,使用buffer.WriteString()函数有更好的性能
5 .
str:="love 123 飞机"
for _,v:=range str{
// fmt.Printf("%T\n",v)
// 输出字符的类型
// fmt.Printf("%v\n",v)
// 返回本来的值
// fmt.Printf("%U\n",v)
// Unicdoe格式
// fmt.Printf("%#v\n",v)
// fmt.Printf("%s\n",v)
// fmt.Printf("%c\n",v)
// 值对应的unicode值
// fmt.Printf("%b\n",v)
// 值对应的二进制
// fmt.Printf("%t\n",v)
// 布尔值
// fmt.Printf("%%\n",v)
// 百分号
fmt.Printf("%p\n",v)
}
utf8,unicode,ascii
1 .Unicdoe,ascii都是一种字符集,为每一个字符分配唯一的id
2 .utf8是一种编码规则,将unicode中的id以某种方式进行编码然后输出
3 .
有疑问加站长微信联系(非本文作者)