1 简介
go1.20 的unsafe包添加了功能SliceData、String和StringData 。
它们完成了独立于实现的切片和字符串操作的函数集,我们一探究竟。
Go 的类型转换规则已扩展为允许 从 slice 直接转换为 array。
语言规范现在定义了比较数组元素和结构字段的确切顺序。
这阐明了在比较过程中出现恐慌时会发生什么。
func SliceData(slice []ArbitraryType) *ArbitraryType
具体如何实现的,无法得知。 我们可以从使用者角度看它的性能与之前的做法有何变化。
2 编码utf8内容
这里说的所谓符文,也就是 rune,在前文有提到过。
RuneError==unicode.ReplacementChar和 MaxRune==unicode.MaxRune在测试中得到了验证。
在本地定义它们可以避免这个包依赖于unicode包。
编码基础。
"错误 "符文或 "Unicode替换字符"
RuneError = '\uFFFD'
RuneSelf以下的字符在一个字节中表示为它们自己。
RuneSelf = 0x80
最大的有效Unicode码位。
MaxRune = '\U0010FFFF'
一个UTF-8编码的Unicode字符的最大字节数。
UTFMax = 4
以下代号范围内的代码点对UTF-8是无效的。
surrogateMin = 0xD800 surrogateMax = 0xDFFF
默认的最低和最高延续字节。
locb = 0b10000000 hicb = 0b10111111
这些常量的名称是为了在下面的表格中提供良好的排列,下面的表格中。
第一个小数点是acceptRanges的索引,或F用于特殊的单字节情况。
特殊的一个字节的情况。第二个小数点是符文长度或特殊的单字节情况下的状态。
acceptRange给出了UTF-8中第二个字节的有效值范围,序列中第二个字节的有效值范围。
var acceptRanges = [16]acceptRange{
0: {locb, hicb},
1: {0xA0, hicb},
2: {locb, 0x9F},
3: {0x90, hicb},
4: {locb, 0x8F},
}
3 FullRune返回参数
FullRune函数的返回值p中的字节是否以一个完整的UTF-8编码的符文开始。
一个无效的编码被认为是一个完整的符文,因为它将转换为一个宽度为1的错误符文 rune。
func FullRune(p []byte) bool {...}
实例:
buf := []byte{228, 184, 150} // 世
fmt.Println(utf8.FullRune(buf))
fmt.Println(utf8.FullRune(buf[:2]))
// Output:
// true
// false
4 对比FullRuneInString与FullRune函数
这两个函数类似,但FullRuneInString输入是一个字符串。
func FullRuneInString(s string) bool {...}
实例:
str := "世"
fmt.Println(utf8.FullRuneInString(str))
fmt.Println(utf8.FullRuneInString(str[:2]))
// Output:
// true
// false
5 DecodeRune 解压编码
解压参数p中的第一个UTF-8编码,并返回符文和它的宽度(字节)。
如果p是空的,则返回(RuneError, 0)。否则,如果编码是无效的,则返回(RuneError, 1)。
这两种情况都是不可能的正确的、非空的UTF-8的结果。
如果一个编码是不正确的UTF-8,或者编码的符文是编码但是超出了范围,或者不是最短的UTF-8编码。
那么编码是无效的。不进行其他验证。
下面的代码模拟了对x == xx的额外检查,并相应地处理ASCII和无效的情况。
这种掩码和或其他的方法可以防止出现额外的分支。
func DecodeRune(p []byte) (r rune, size int) {...}
实例:
b := []byte("Hello, 世界")
for len(b) > 0 {
r, size := utf8.DecodeRune(b)
fmt.Printf("%c %v\n", r, size)
b = b[size:]
}
// Output:
// H 1
// e 1
// l 1
// l 1
// o 1
// , 1
// 1
// 世 3
// 界 3
6 对比DecodeRuneInString与DecodeRune
两个函数类似,DecodeRuneInString其输入是一个字符串。
如果s是是空的,它会返回(RuneError, 0)。否则,如果编码是无效的,它会返回(RuneError, 1)。
对于正确的、非空的UTF-8来说,这两种结果都是不可能的。
如果一个编码是不正确的UTF-8,编码的符文是编码但是超出了范围,或者不是最短的UTF-8编码。
那么传入的编码是无效的。不进行其他验证。
func DecodeRuneInString(s string) (r rune, size int) {...}
str := "Hello, 世界"
for len(str) > 0 {
r, size := utf8.DecodeRuneInString(str)
fmt.Printf("%c %v\n", r, size)
str = str[size:]
}
// Output:
// H 1
// e 1
// l 1
// l 1
// o 1
// , 1
// 1
// 世 3
// 界 3
7 DecodeLastRune解压参数
该解码函数的p中的最后一个UTF-8编码并返回符文和其宽度(字节)。
如果参数p是空的,则返回(RuneError, 0)。
否则,如果参数p的编码是无效的,则返回(RuneError, 1)。
这两种情况都是不可能的,正确的、非空的UTF-8的结果。
如果一个编码是不正确的UTF-8,编码的符文是编码,但是超出了范围,或者不是最短的UTF-8编码。
那么编码是无效的。不进行其他验证。
func DecodeLastRune(p []byte) (r rune, size int) {...}
使用实例:
b := []byte("Hello, 世界")
for len(b) > 0 {
r, size := utf8.DecodeLastRune(b)
fmt.Printf("%c %v\n", r, size)
b = b[:len(b)-size]
}
// Output:
// 界 3
// 世 3
// 1
// , 1
// o 1
// l 1
// l 1
// e 1
// H 1
8 对比解码函数DecodeLastRuneInString与DecodeLastRune
它们类似,DecodeLastRuneInString输入是一个字符串。
如果s是空的,则返回(RuneError, 0)。
否则,如果编码是无效的,它返回(RuneError, 1)。
对于正确的非空的UTF-8来说,这两种结果都是不可能的。
如果一个编码是不正确的UTF-8,编码的符文是编码但是超出了范围,或者不是最短的UTF-8编码。
那么编码是无效的。不进行其他验证。
func DecodeLastRuneInString(s string) (r rune, size int) {...}
实例:
str := "Hello, 世界"
for len(str) > 0 {
r, size := utf8.DecodeLastRuneInString(str)
fmt.Printf("%c %v\n", r, size)
str = str[:len(str)-size]
}
// Output:
// 界 3
// 世 3
// 1
// , 1
// o 1
// l 1
// l 1
// e 1
// H 1
9 RuneLen返回对符文进行编码所需的字节数。
如果符文不是一个可以用UTF-8编码的有效值,则返回-1。
func RuneLen(r rune) int {...}
实例:
fmt.Println(utf8.RuneLen('a'))
fmt.Println(utf8.RuneLen('界'))
// Output:
// 1
// 3
10 符文编码函数EncodeRune
将符文的UTF-8编码写进参数p(必须足够大
如果符文超出了范围,它就写出RuneError的编码,它返回写入的字节数。
func EncodeRune(p []byte, r rune) int {...}
实例: 正常使用
r := '世'
buf := make([]byte, 3)
n := utf8.EncodeRune(buf, r)
fmt.Println(buf)
fmt.Println(n)
// Output:
// [228 184 150]
// 3
实例:索引越界
runes := []rune{
// Less than 0, out of range.
-1,
// Greater than 0x10FFFF, out of range.
0x110000,
// The Unicode replacement character.
utf8.RuneError,
}
for i, c := range runes {
buf := make([]byte, 3)
size := utf8.EncodeRune(buf, c)
fmt.Printf("%d: %d %[2]s %d\n", i, buf, size)
}
// Output:
// 0: [239 191 189] � 3
// 1: [239 191 189] � 3
// 2: [239 191 189] � 3
11 符文扩充函数AppendRune
符文扩充函数将r的UTF-8编码附加到p的末尾,并且返回扩展的缓冲区。
如果符文超出了范围。
它将附加RuneError的编码。
func AppendRune(p []byte, r rune) []byte {...}
实例:
buf1 := utf8.AppendRune(nil, 0x10000)
buf2 := utf8.AppendRune([]byte("init"), 0x10000)
fmt.Println(string(buf1))
fmt.Println(string(buf2))
// Output:
// 𐀀
// init𐀀
12 符文计量RuneCount
符文计量函数RuneCount返回p中符文的数量。
错误的和短小的编码被视为宽度为1字节的单一符文。
func RuneCount(p []byte) int {...}
实例:
buf := []byte("Hello, 世界")
fmt.Println("bytes =", len(buf))
fmt.Println("runes =", utf8.RuneCount(buf))
// Output:
// bytes = 13
// runes = 9
13 对比符文计量函数RuneCountInString与RuneCount
RuneCountInString输入是一个字符串, 返回符文数量。
func RuneCountInString(s string) (n int) {...}
实例:
str := "Hello, 世界"
fmt.Println("bytes =", len(str))
fmt.Println("runes =", utf8.RuneCountInString(str))
// Output:
// bytes = 13
// runes = 9
14 符文首字符RuneStart
该函数RuneStart,报告该字节是否为编码后的第一个字节,可能是无效的符文。
第二个和随后的字节总是将前两个位设置为10。
func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
实例:
buf := []byte("a界")
fmt.Println(utf8.RuneStart(buf[0]))
fmt.Println(utf8.RuneStart(buf[1]))
fmt.Println(utf8.RuneStart(buf[2]))
// Output:
// true
// true
// false
15 合法性检查函数Valid
报告参数p是否完全由有效的UTF-8编码的符文组成。
这种优化避免了在生成p[8:]的代码时重新计算容量的需要。
在生成p[8:]的代码时需要重新计算容量,使其与ValidString相媲美。
ValidString,后者在长ASCII字符串上快20%。
将两个32位的负载结合起来,可以使相同的代码用于32位和64位平台。
编译器可以为first32和second32生成一个32位的负载,在许多平台上。参见test/codegen/memcombine.go。
func Valid(p []byte) bool {...}
实例:
valid := []byte("Hello, 世界")
invalid := []byte{0xff, 0xfe, 0xfd}
fmt.Println(utf8.Valid(valid))
fmt.Println(utf8.Valid(invalid))
// Output:
// true
// false
16 ValidString
符文字符检查函数ValidString报告s是否完全由有效的UTF-8编码的符文组成。
每次迭代检查并跳过8个字节的ASCII字符。
将两个32位的负载结合起来,可以使相同的代码用于用于32位和64位平台。
编译器可以为first32和second32生成一个32位的负载。
在许多平台上。参见test/codegen/memcombine.go。
func ValidString(s string) bool {...}
实例:
valid := "Hello, 世界"
invalid := string([]byte{0xff, 0xfe, 0xfd})
fmt.Println(utf8.ValidString(valid))
fmt.Println(utf8.ValidString(invalid))
// Output:
// true
// false
17 编码合法性检查ValidRune
编码合法性检查函数报告r是否可以被合法地编码为UTF-8。
超出范围的代码点或代用半数是非法的。
func ValidRune(r rune) bool {...}
实例:
valid := 'a'
invalid := rune(0xfffffff)
fmt.Println(utf8.ValidRune(valid))
fmt.Println(utf8.ValidRune(invalid))
// Output:
// true
// false