引入

用于保存一段文本内容,Go 的字符串是 UTF-8 编码的。字符串是程序里用得最多的类型之一,处理用户输入、拼接日志、解析文件都离不开它。Go 的字符串是不可变的,这个设计和很多语言不一样,搞清楚它的特性和常用操作方式很重要。

正文

定义

定义

字符串是一段不可变的 UTF-8 编码字节序列。Go 里用双引号 "…" 创建解释字符串,用反引号 `…` 创建原始字符串。strings 包提供了丰富的字符串操作函数。

语法

// 解释字符串(支持转义)
var s1 string = "hello\nworld"
 
// 原始字符串(不转义)
var s2 string = `hello\nworld`
 
// 字符串拼接
var s3 string = "hello" + " " + "world"

例子

创建字符串

s1 := "hello"           // 解释字符串
s2 := `hello\nworld`    // 原始字符串,\n 不会被转义
s3 := ""                // 空字符串
 
fmt.Println(s1)  // hello
fmt.Println(s2)  // hello\nworld

双引号字符串支持转义字符(\n\t\\ 等),反引号字符串原样保留所有内容,适合写多行文本或正则表达式。

字符串拼接

// + 运算符
s := "hello" + " " + "world"
 
// fmt.Sprintf
s = fmt.Sprintf("%s is %d years old", "Tom", 20)
 
// strings.Builder(大量拼接时性能最好)
var sb strings.Builder
sb.WriteString("hello")
sb.WriteString(" ")
sb.WriteString("world")
s = sb.String()

少量拼接用 +,需要格式化用 fmt.Sprintf,循环里大量拼接用 strings.Builder

常用操作

import "strings"
 
s := "Hello, World!"
 
strings.Contains(s, "World")     // true
strings.HasPrefix(s, "Hello")    // true
strings.HasSuffix(s, "!")        // true
strings.Index(s, "World")        // 7
strings.Replace(s, "World", "Go", 1)  // "Hello, Go!"
strings.ToLower(s)               // "hello, world!"
strings.ToUpper(s)               // "HELLO, WORLD!"
strings.TrimSpace("  hi  ")     // "hi"
strings.Split("a,b,c", ",")     // ["a" "b" "c"]
strings.Join([]string{"a", "b"}, "-")  // "a-b"
strings.Repeat("ab", 3)          // "ababab"
strings.Count("banana", "a")     // 3

长度和索引

s := "你好"
 
len(s)          // 6(字节数,不是字符数)
utf8.RuneCountInString(s)  // 2(字符数)
 
// 按字节索引
s[0]            // 228(第一个字节)
 
// 按字符遍历
for i, r := range s {
    fmt.Printf("%d: %c\n", i, r)
}
// 0: 你
// 3: 好

len() 返回的是字节数,不是字符数。中文字符在 UTF-8 里占 3 个字节,所以 "你好" 的长度是 6。

字符串和字节切片互转

s := "hello"
 
// 字符串转字节切片
b := []byte(s)   // [104 101 108 108 111]
 
// 字节切片转字符串
s2 := string(b)  // "hello"

因为字符串不可变,所以每次转换都会复制一份数据

字符串比较

s1 := "abc"
s2 := "abc"
 
s1 == s2  // true(逐字节比较)

Go 的字符串比较是逐字节的,不是按 Unicode 码点比较。

常见写法

写法说明
"hello"解释字符串,支持转义
`raw`原始字符串,不转义
s1 + s2简单拼接
fmt.Sprintf("%s", s)格式化拼接
strings.Builder高性能大量拼接
strings.Contains(s, sub)判断是否包含
strings.Split(s, sep)按分隔符切割
strings.Join(ss, sep)切片拼接为字符串
[]byte(s)字符串转字节切片
string(b)字节切片转字符串

特点

  • 字符串是不可变的,任何修改操作都会创建新字符串
  • len() 返回字节数,不是字符数,中文等多字节字符要注意
  • range 遍历字符串时,迭代的是 Unicode 码点rune),不是字节
  • 双引号字符串支持转义,反引号字符串原样保留
  • strings 包是字符串操作的首选工具
  • 大量拼接用 strings.Builder,性能比 + 好很多
  • 字符串的零值是 ""(空字符串),不是 nil

理解

Go 的字符串设计核心就是不可变 + UTF-8。不可变意味着安全(多线程不用加锁)但也意味着每次修改都是新对象。UTF-8 意味着能正确处理全球文字,但 len() 返回的是字节数不是字符数这个坑要记住。日常操作用 strings 包就够了,大量拼接记得用 strings.Builder

引出

字符串里经常要处理数字文本,比如把 "42" 变成 42。接下来看 Go 数字,了解 Go 里整型和浮点型的详细用法,以及数字和字符串之间的转换。