Skip to content

05 string 的使用和实践

  • string 是一种基本数据类型,用于表示不可变的 Unicode 字符串。
  • 字符串类型在 Go 中有其独特的特性和操作方式,它以字节数组([]byte)形式存储,并且具备编码、切片等强大的特性。
  • 声明字符串后,字符串默认值是 ""(空字符串)。
  • string 是值类型,不是引用类型。
  • 特点:
    • 数据不可变:string 是值类型,不是引用类型
    • 默认值可用:声明后默认值为 ""
    • 支持 + 或者 += 运算:可以使用 + 或者 += 连接运算符连接两个字符串
    • 支持 len() 获取长度:可以使用 len() 函数获取字符串的长度
    • 支持 for-range 遍历:可以使用 for-range 语法遍历字符串中的每个字符
    • 支持 [] 切片操作:可以使用 [] 操作符获取字符串中的单个字节或字符
    • 支持 ==!=<><=>= 比较运算:可以使用比较运算符比较两个字符串
    • 支持多行定义:可以使用反引号 ` ` 定义多行字符串

基本定义与使用

Go 中的字符串可以用双引号 "" 或反引号 ` ` 包围:

go
package main

import "fmt"

func main() {
    var s1 string = "Hello, Go!"          // 使用双引号定义字符串
    var s2 string = `This is a raw string literal.`  // 使用反引号定义原始字符串

    fmt.Println(s1)  // 输出:Hello, Go!
    fmt.Println(s2)  // 输出:This is a raw string literal.
}

字符串类型的特点:

  1. 不可变性:字符串一旦创建就不能修改,每次对字符串进行操作都会返回一个新的字符串。
  2. 存储方式:字符串在底层是一个字节数组,支持通过索引访问单个字节,但不能直接修改。

字符串的声明与初始化

字符串的声明方式有多种,可以使用 var 关键字、短变量声明 :=、或者直接赋值。

go
var str1 string = "Hello, World!"  // 使用 var 关键字
str2 := "Go Programming"           // 使用 := 短变量声明
str3 := ""                         // 声明一个空字符串

字符串的长度与遍历

可以使用 len() 函数来获取字符串的长度。注意,len() 返回的是字符串中字节的数量而不是字符的数量。

go
str := "Hello, 世界"
fmt.Println(len(str))  // 输出:13(因为 '世' 和 '界' 是 3 个字节)

// 遍历字符串时可以使用 for-range 语法
for i, ch := range str {
    fmt.Printf("Index: %d, Character: %c\n", i, ch)
}

for-range 循环中,每次迭代都会返回索引 i 和 Unicode 码点(rune)形式的字符 ch,而不是字节。

字符串的切片操作

字符串可以像数组一样进行切片操作,切片时需要指定起始索引和结束索引。注意:字符串切片返回的依然是字符串。

go
str := "Hello, Go!"
fmt.Println(str[0:5])  // 输出:Hello
fmt.Println(str[7:])   // 输出:Go!

注意

切片操作基于字节而非字符,这意味着对于包含多字节字符(如中文、特殊符号等)的字符串,直接使用切片可能导致乱码。

字符串的连接

Go 提供了多种字符串连接方式。最常用的是使用 + 操作符,也可以使用 fmt.Sprintfstrings.Join

go
str1 := "Hello"
str2 := "Go"
result := str1 + ", " + str2 + "!"  // 使用 + 操作符连接字符串
fmt.Println(result)  // 输出:Hello, Go!

其他连接方式:

  1. fmt.Sprintf 格式化字符串:

    go
    str1 := "Hello"
    str2 := "Go"
    result := fmt.Sprintf("%s, %s!", str1, str2)
    fmt.Println(result)  // 输出:Hello, Go!
  2. strings.Join 连接字符串切片:

    go
    import "strings"
    strSlice := []string{"Hello", "Go", "Language"}
    result := strings.Join(strSlice, " ")  // 使用空格连接切片中的字符串
    fmt.Println(result)  // 输出:Hello Go Language

字符串比较

Go 中的字符串比较可以直接使用 ==!=<> 等运算符。比较时按字典序进行。

go
str1 := "Hello"
str2 := "World"

fmt.Println(str1 == str2)  // 输出:false
fmt.Println(str1 < str2)   // 输出:true(因为 "Hello" 在字典序中小于 "World")

字符串包含与查找

可以使用 strings 包提供的函数来进行包含、查找、前缀和后缀匹配等操作。

go
import "strings"

str := "Hello, Go!"

fmt.Println(strings.Contains(str, "Go"))       // 检查是否包含子字符串 "Go",输出:true
fmt.Println(strings.HasPrefix(str, "Hello"))   // 检查前缀是否为 "Hello",输出:true
fmt.Println(strings.HasSuffix(str, "!"))       // 检查后缀是否为 "!",输出:true
fmt.Println(strings.Index(str, "Go"))          // 查找 "Go" 的索引位置,输出:7

字符串替换

可以使用 strings.Replace 进行字符串替换。

go
import "strings"

str := "Hello, Go! Go!"
newStr := strings.Replace(str, "Go", "Golang", 1)  // 只替换第一个 "Go"
fmt.Println(newStr)  // 输出:Hello, Golang! Go!

newStr = strings.Replace(str, "Go", "Golang", -1)  // 替换所有 "Go"
fmt.Println(newStr)  // 输出:Hello, Golang! Golang!

字符串分割

可以使用 strings.Split 分割字符串为一个切片:

go
import "strings"

str := "Go,Python,Java"
splitStr := strings.Split(str, ",")  // 按逗号分割字符串
fmt.Println(splitStr)  // 输出:[Go Python Java]

字符串转换

  • 字节数组与字符串的转换

    • []byte(str) 将字符串转换为字节切片。

    • string([]byte) 将字节切片转换为字符串。

      go
      str := "Hello"
      bytes := []byte(str)  // 字符串转为字节数组
      fmt.Println(bytes)    // 输出:[72 101 108 108 111]
      
      newStr := string(bytes)  // 字节数组转为字符串
      fmt.Println(newStr)      // 输出:Hello
  • 大小写转换

    go
    import "strings"
    
    str := "Hello, Go!"
    fmt.Println(strings.ToUpper(str))  // 转换为大写:HELLO, GO!
    fmt.Println(strings.ToLower(str))  // 转换为小写:hello, go!

多行字符串与原始字符串

使用反引号(`)定义多行字符串或原始字符串。

go
str := `This is a raw string literal.
It can span multiple lines without escaping characters like \n or \t.
`
fmt.Println(str)  // 输出:This is a raw string literal. It can span multiple lines without escaping characters like \n or \t.

反引号定义的字符串可以包含特殊字符而不需要转义,例如 \n\t 等。

字符串与 rune

在 Go 中,字符串是 UTF-8 编码的字节序列。如果需要处理 Unicode 字符,可以使用 rune 类型(表示 Unicode 码点)。

go
str := "Hello, 世界"
runes := []rune(str)  // 将字符串转换为 rune 切片
for _, r := range runes {
    fmt.Printf("%c ", r)  // 逐个打印 Unicode 字符
}
// 输出:H e l l o ,   世 界

字符串的性能优化

当需要对字符串进行大量拼接时,使用 strings.Builder 会更高效:

go
import "strings"

var builder strings.Builder
builder.WriteString("Hello")
builder.WriteString(", ")
builder.WriteString("Go!")

result := builder.String()
fmt.Println(result)  // 输出:Hello, Go!

使用 strings.Builder 可以避免频繁的字符串拷贝,从而提升性能。