本文视频地址
内置的 string 类型。无论是字符串常量、字符串变量还是出现的字符串字面值,都被统一设置为 string。
const (
s = “Hello"
)
func main() {
var s1 string = “Golang"
fmt.Printf("%T\n", s) // string
fmt.Printf("%T\n", s1) // string
fmt.Printf("%T\n", “Cool Golang") // string
}
Go string 类型具有如下功能特点:
string 类型的数据是不可变的
一旦声明了一个 string 类型的标识符,无论是变量还是常量,那么该标识符所指代的数据在整个程序的生命周期内便无法被更改。
func main() {
var s = "hello Golang"
fmt.Println("原始值:", s)
sl := []byte(s)
sl[0] = 't'
fmt.Println("切片:", string(sl))
fmt.Println("修改后的字符串:", s)
}
原始值: hello Golang
切片: tello Golang
修改后的字符串: hello Golang
在例子中我们做了如下操作:
1 创建一个字符串
2 通过将 string 转换为一个 slice 并通过该 slice 对其内容进行修改。对 string 进行 slice 转换后,Go 编译器会为 slice 变量重新分配底层存储而不是共用 string 的底层存储,因此对 slice 的修改并未对原 string 的数据产生任何影响。
零值可用
var x string
fmt.Println(x) // x = ""
fmt.Println(len(x)) // 0
Go string 类型数据是不可变的,因此一旦有了初值后,那块数据就不会改变,其长度也不会改变。Go 将这个长度作为一个字段存储在了运行时的 string 类型结构中了。这样获取 string 长度的操作,即 len(s) 实际上就是读取存储在运行时中的那个长度值,这是一个代价极低的 O(1)操作。
支持通过+/+=操作符进行字符串连接
s := “Hello, "
s = s + “World, "
s += " Cool"
fmt.Println(s) // Hello,World, Cool
支持各种比较关系操作符:==、!= 、>=、<=、> 和 <
1 如果两个字符串的 length 不相同,那么无需比较具体字符串数据,断定两个字符串是不同的。
2 如果 length 相同,则要进一步判断数据指针是否指向同一块底层存储数据。
如果相同,则两个字符串是等价的。
如果不同,则还需进一步去比对实际的数据内容。
对非 ASCII 字符提供原生支持
Go 源文件的字符编码默认为 UTF-8 编码。以 UTF-8 编码作为内码存储将对应的文本存储在内存当中的。
s := "面向加薪学习"
rs := []rune(s)
bs := []byte(s)
for i, v := range rs {
var utf8Bytes []byte
for j := i * 3; j < (i+1)*3; j++ {
utf8Bytes = append(utf8Bytes, bs[j])
}
fmt.Printf("%s => %X => %X\n", string(v), v, utf8Bytes)
}
面 => 9762 => E99DA2
向 => 5411 => E59091
加 => 52A0 => E58AA0
薪 => 85AA => E896AA
学 => 5B66 => E5ADA6
习 => 4E60 => E4B9A0
字符串变量 s 中存储的文本是”面向加薪学习“汉字字符(非 ASCII 字符范畴),输出每个中文字符对应的 Unicode 码点,一个 rune 对应一个码点。UTF-8 编码是 Unicode 码点的一种字符编码形式,也是最常用的一种编码格式,也是 Go 默认的字符编码格式。我们还可以使用其他字符编码格式来映射 Unicode 码点,比如:UTF-16 等。
在 UTF-8 中,大多数中文字符都使用三个字节表示。[]byte(s)的转型让我们获得了 s 底层存储的底层数组,从而我们得到了每个汉字字符对应的 UTF-8 编码字节。
Go 语言直接提供了通过反引号(`)构造“所见即所得”的多行字符串的方法。
字符串的内部表示
Go string 在运行时表示为下面结构:
// $GOROOT/src/runtime/string.go
type stringStruct struct {
str unsafe.Pointer
len int
}
上面结构体,已经告诉我们,运行时的string它本身并不真正存储数据,而仅是由一个指向底层存储的指针和字符串的长度字段组成。
字符串的高效构造
Go 还提供了其他一些构造字符串的方法,如下:
使用 strings.Builder
使用 bytes.Buffer
使用 strings.Join
使用 fmt.Sprintf