本节重点:
- 学会 sting 的基本使用
字符串在 Go 中值得特别提及,因为与其他语言相比,string
的实现方式同其他语言略有不同。
什么是字符串?
字符串是 Go 中的字节切片。可以通过将一组字符括在双引号中来创建字符串" "
。
让我们看个创建string
并打印它的简单示例。
package mainimport ( "fmt"
)func main() { web := "https:www.gotribe.cn"fmt.Println(web)
}
上面的程序将打印https:www.gotribe.cn
.
Go 中的字符串是兼容Unicode编码的,并且是UTF-8编码的。
访问字符串的单个字节
由于字符串是字节切片,因此可以访问字符串的每个字节。
package mainimport ( "fmt"
)func printBytes(s string) { fmt.Printf("Bytes: ")for i := 0; i < len(s); i++ {fmt.Printf("%x ", s[i])}
}func main() { web := "https:www.gotribe.cn"fmt.Printf("String: %s\n", web)printBytes(web)
}
%s
是打印字符串的格式说明符。在16行号,打印输入字符串。在上面程序的第9 行中,len(s)
返回字符串中的字节数,我们使用for
循环以十六进制格式符打印这些字节。%x
是十六进制的格式说明符。上述程序输出
String: https:www.gotribe.cn
Bytes: 68 74 74 70 73 3a 77 77 77 2e 67 6f 74 72 69 62 65 2e 63 6e
访问字符串的单个字符
我们稍微修改一下上面的程序来打印字符串的字符。
package mainimport ("fmt"
)func printBytes(s string) {fmt.Printf("Bytes: ")for i := 0; i < len(s); i++ {fmt.Printf("%x ", s[i])}
}func printChars(s string) {fmt.Printf("Characters: ")for i := 0; i < len(s); i++ {fmt.Printf("%c ", s[i])}
}func main() {web := "https:www.gotribe.cn"fmt.Printf("String: %s\n", web)printBytes(web)fmt.Printf("\n")printChars(web)
}
在上面程序的第 17 行, %c
格式说明符用于在printChars
方法中打印字符串的字符。程序打印:
String: https:www.gotribe.cn
Bytes: 68 74 74 70 73 3a 77 77 77 2e 67 6f 74 72 69 62 65 2e 63 6e
Characters: h t t p s : w w w . g o t r i b e . c n
上面的程序看起来像是访问字符串中单个字符的合法方式,但它有一个严重的错误。让我们找出那个错误是什么。
package mainimport ("fmt"
)func printBytes(s string) {fmt.Printf("Bytes: ")for i := 0; i < len(s); i++ {fmt.Printf("%x ", s[i])}
}func printChars(s string) {fmt.Printf("Characters: ")for i := 0; i < len(s); i++ {fmt.Printf("%c ", s[i])}
}func main() {web := "https:www.gotribe.cn"fmt.Printf("String: %s\n", web)printBytes(web)fmt.Printf("\n")printChars(web)fmt.Printf("\n\n")web = "Señor"fmt.Printf("String: %s\n", web)printBytes(web)fmt.Printf("\n")printChars(web)
}
上述程序的输出是
String: https:www.gotribe.cn
Bytes: 68 74 74 70 73 3a 77 77 77 2e 67 6f 74 72 69 62 65 2e 63 6e
Characters: h t t p s : w w w . g o t r i b e . c n String: Señor
Bytes: 53 65 c3 b1 6f 72
Characters: S e à ± o r
上面程序的第 33 行,我们尝试将 “Señor” 中的每个字符打印出来,但是却得到了 “Señor”。为什么这个程序在 “https:www.gotribe.cn” 上运行正常,但是不适用于 “Señor” 呢?因为 ñ 的 Unicode 码点是 U+00F1,因而它的 UTF-8 编码占了两个字节:c3
和 b1
。上面的程序假定每个码点只有一个字节长度,因此会发生错误。在 UTF-8 编码中,一个码点可能会占一个以上的字节。 在这种情况下,我们需要 rune
来帮助解决问题。
rune
rune
是 Go 中的内置类型,它是 int32 的别名。Rune 表示 Go 中的 Unicode 代码点。代码点占用多少字节并不重要,它可以用一个符文来表示。让我们修改上面的程序以使用符文打印字符。
package mainimport ("fmt"
)func printBytes(s string) {fmt.Printf("Bytes: ")for i := 0; i < len(s); i++ {fmt.Printf("%x ", s[i])}
}func printChars(s string) { fmt.Printf("Characters: ")runes := []rune(s)for i := 0; i < len(runes); i++ {fmt.Printf("%c ", runes[i])}
}
func main() {web := "https:www.gotribe.cn"fmt.Printf("String: %s\n", web)printBytes(web)fmt.Printf("\n")printChars(web)fmt.Printf("\n\n")web = "Señor"fmt.Printf("String: %s\n", web)printBytes(web)fmt.Printf("\n")printChars(web)
}
在上面的程序的 第16行 中,字符串被转换为rune切片。然后我们循环它并显示字符。输出结果为:
String: https:www.gotribe.cn
Bytes: 68 74 74 70 73 3a 77 77 77 2e 67 6f 74 72 69 62 65 2e 63 6e
Characters: h t t p s : w w w . g o t r i b e . c n String: Señor
Bytes: 53 65 c3 b1 6f 72
Characters: S e ñ o r
这时候结果就正确了。
字符串连接
在 Go 中有多种方法可以执行字符串连接。让我们来看看其中的几个。
执行字符串连接的最简单方法是使用+
运算符。
ackage mainimport ( "fmt"
)func main() { string1 := "Go"string2 := "is awesome"result := string1 + " " + string2fmt.Println(result)
}
在上面的程序中,第 10 行。string1
与中间的空格和string2
连接。该程序打印,Go is awesome
连接字符串的第二种方法是使用 fmt 包的Sprintf函数。
该Sprintf
函数根据输入格式说明符格式化字符串并返回结果字符串。让我们用Sprintf
函数重写上面的程序。
package mainimport ( "fmt"
)func main() { string1 := "Go"string2 := "is awesome"result := fmt.Sprintf("%s %s", string1, string2)fmt.Println(result)
}
上面程序的 第10行%s %s
格式是作为Sprintf
参数输入两个字符串,它们之间有一个空格。这将连接两个字符串。结果字符串存储在result
中. 该程序打印,Go is awesome
注意点:
- 字符串在 Go 中是不可变的。一旦创建了字符串,就无法更改它。
- utf8包提供了
RuneCountInString(s string) (n int)
来获取字符串的长度。一些 Unicode 字符的代码点占据了超过 1 个字节。len
用于找出这些字符串的长度将返回不正确的字符串长度。