字符串基础 #

一、字符串概述 #

1.1 字符串特点 #

  • 不可变:创建后不能修改
  • UTF-8编码
  • 双引号或反引号定义
  • 值类型

二、字符串定义 #

2.1 双引号字符串 #

go
s := "Hello, World!"
fmt.Println(s)

支持转义字符:

go
s := "Hello\nWorld\t!"
fmt.Println(s)

2.2 反引号字符串 #

原始字符串,不支持转义:

go
s := `Hello
World
"引号"`
fmt.Println(s)

2.3 字符串零值 #

go
var s string
fmt.Println(s)      // 空字符串
fmt.Println(s == "") // true

三、字符串不可变性 #

3.1 不能修改 #

go
s := "Hello"
s[0] = 'h'  // 错误:字符串不可变

3.2 重新赋值 #

go
s := "Hello"
s = "World"  // 可以重新赋值

3.3 修改需要转换 #

go
s := "Hello"
b := []byte(s)
b[0] = 'h'
s = string(b)
fmt.Println(s)  // hello

四、字符串长度 #

4.1 len函数 #

返回字节数:

go
s := "Hello"
fmt.Println(len(s))  // 5

s2 := "世界"
fmt.Println(len(s2))  // 6(UTF-8编码,每个中文3字节)

4.2 字符数 #

go
s := "世界"
fmt.Println(utf8.RuneCountInString(s))  // 2

4.3 遍历字符 #

go
s := "世界"
for i, r := range s {
    fmt.Printf("%d: %c\n", i, r)
}

五、UTF-8编码 #

5.1 编码规则 #

字符范围 编码长度
ASCII (0-127) 1字节
其他BMP字符 2-3字节
补充字符 4字节

5.2 中文编码 #

go
s := "中"
fmt.Println(len(s))  // 3

b := []byte(s)
fmt.Printf("%x %x %x\n", b[0], b[1], b[2])  // e4 b8 ad

5.3 rune类型 #

rune是int32别名,表示Unicode码点:

go
var r rune = '中'
fmt.Printf("%c\n", r)  // 中
fmt.Printf("%U\n", r)  // U+4E2D
fmt.Printf("%d\n", r)  // 20013

六、字符串遍历 #

6.1 按字节遍历 #

go
s := "Hello"
for i := 0; i < len(s); i++ {
    fmt.Printf("%d: %c\n", i, s[i])
}

6.2 按rune遍历 #

go
s := "世界"
for i, r := range s {
    fmt.Printf("%d: %c\n", i, r)
}

6.3 转换为rune切片 #

go
s := "世界"
runes := []rune(s)
fmt.Println(len(runes))  // 2

for i, r := range runes {
    fmt.Printf("%d: %c\n", i, r)
}

七、字符串连接 #

7.1 使用+号 #

go
s := "Hello" + " " + "World"
fmt.Println(s)

7.2 使用fmt.Sprintf #

go
name := "World"
s := fmt.Sprintf("Hello, %s!", name)
fmt.Println(s)

7.3 使用strings.Builder #

go
var builder strings.Builder
builder.WriteString("Hello")
builder.WriteString(" ")
builder.WriteString("World")
s := builder.String()
fmt.Println(s)

7.4 使用strings.Join #

go
parts := []string{"Hello", "World"}
s := strings.Join(parts, " ")
fmt.Println(s)

八、字符串比较 #

8.1 相等比较 #

go
s1 := "Hello"
s2 := "Hello"
fmt.Println(s1 == s2)  // true

8.2 大小比较 #

go
s1 := "apple"
s2 := "banana"
fmt.Println(s1 < s2)   // true(字典序)
fmt.Println(s1 > s2)   // false

8.3 忽略大小写比较 #

go
import "strings"

s1 := "Hello"
s2 := "HELLO"
fmt.Println(strings.EqualFold(s1, s2))  // true

九、字符串与字节切片 #

9.1 字符串转字节切片 #

go
s := "Hello"
b := []byte(s)
fmt.Println(b)  // [72 101 108 108 111]

9.2 字节切片转字符串 #

go
b := []byte{72, 101, 108, 108, 111}
s := string(b)
fmt.Println(s)  // Hello

9.3 不安全转换 #

避免复制的转换:

go
import "unsafe"

func stringToBytes(s string) []byte {
    return unsafe.Slice(unsafe.StringData(s), len(s))
}

func bytesToString(b []byte) string {
    return unsafe.String(&b[0], len(b))
}

十、实际应用 #

10.1 判断字符串是否为空 #

go
func isEmpty(s string) bool {
    return s == ""
}

func isBlank(s string) bool {
    return strings.TrimSpace(s) == ""
}

10.2 字符串截取 #

go
func substring(s string, start, end int) string {
    runes := []rune(s)
    if start < 0 {
        start = 0
    }
    if end > len(runes) {
        end = len(runes)
    }
    return string(runes[start:end])
}

s := "世界你好"
fmt.Println(substring(s, 0, 2))  // 世界

10.3 反转字符串 #

go
func reverse(s string) string {
    runes := []rune(s)
    for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
        runes[i], runes[j] = runes[j], runes[i]
    }
    return string(runes)
}

fmt.Println(reverse("Hello"))  // olleH

十一、总结 #

字符串要点:

特性 说明
定义 双引号或反引号
不可变 创建后不能修改
编码 UTF-8
长度 len()返回字节数
字符 rune类型表示Unicode码点

关键点:

  1. 不可变性:字符串创建后不能修改
  2. UTF-8编码:Go字符串默认UTF-8
  3. rune类型:表示Unicode字符
  4. 长度计算:len()返回字节数,utf8.RuneCountInString()返回字符数
  5. 高效连接:使用strings.Builder

准备好学习字符串操作了吗?让我们进入下一章!

最后更新:2026-03-26