字符串是不可变字节(byte
)序列,默认值是"",而不是nil
。
使用 “`” 定义的原始字符串(raw strubg
),支持跨行。字符串支持 !=、==、<、>、+、+=
操作符。允许以索引号访问字节数组,但不能获取元素地址。
使用 for
遍历字符串时,分 byte
和 rune
两种方式。
转换
修改字符串,需将其转换为可变类型([]byte
或 []rune
),待完成后再转换回来。这个过程将重新分配内存,并复制数据。这个转换过程有一定的性能损失。要想获得更好的性能可以使用 “非安全” 的方式进行改善。
func bytesToString(bs []byte) string {
return *(*string)(unsafe.Pointer(&bs))
}
亦可以用同样的方式将 string
转换为 []byte
。只不过得到的字节序列是不可修改的,当尝试修改时,会得到如下类似错误:
unexpected fault address 0x1066146
fatal error: fault
[signal SIGBUS: bus error code=0x2 addr=0x1066146 pc=0x104bff0]
动态构建字符串
用 +
拼接字符串时,每次都会重新分配内存。在拼接超多字符串时,性能将显得极差。
改进的思路是分配足够的内存空间,减少内存分配的次数。常用方法是 strings.Join
函数,其实现如下:
func Join(a []string, sep string) string {
if len(a) == 0 {
return ""
}
if len(a) == 1 {
return a[0]
}
n := len(sep) * (len(a) - 1)
for i := 0; i < len(a); i++ {
n += len(a[i])
}
b := make([]byte, n)
bp := copy(b, a[0])
for _, s := range a[1:] {
bp += copy(b[bp:], sep)
bp += copy(b[bp:], s)
}
return string(b)
}
结合前面的内容,可以对 Join
函数稍作修改,减少一次内存分配和内容复制操作。
func Join(a []string, sep string) string {
……
return toString(b)
}