ZetCode

Golang fmt.Appendf 函数

最后修改时间 2025 年 5 月 8 日

本教程将解释如何在 Go 中使用 fmt.Appendf 函数。我们将通过实际示例介绍高效的字符串操作,涵盖字符串格式化的基础知识。

fmt.Appendf 函数根据格式说明符进行格式化,并将结果追加到字节切片。在构建字符串时,它比 fmt.Sprintf 更高效。

在 Go 1.19+ 中,fmt.Appendf 提供了一种通过重用已分配内存来构建字符串的高效方法。当追加到具有足够容量的现有切片时,它可以避免分配。

fmt.Appendf 基本示例

fmt.Appendf 最简单的用法是将格式化的文本追加到字节切片。本示例演示了基本的字符串格式化和追加。

basic_appendf.go
package main

import (
    "fmt"
)

func main() {
    buf := []byte("Existing content: ")
    
    name := "Alice"
    age := 30
    
    buf = fmt.Appendf(buf, "Name: %s, Age: %d", name, age)
    
    fmt.Println(string(buf))
}

代码以初始字节切片开始,并追加格式化内容。输出将原始内容和新内容合并到一个字符串中。

多次追加

fmt.Appendf 可以对同一个切片调用多次。本示例展示了通过多次追加进行增量字符串构建。

multiple_append.go
package main

import (
    "fmt"
)

func main() {
    buf := []byte{}
    
    for i := 1; i <= 5; i++ {
        buf = fmt.Appendf(buf, "Iteration %d, ", i)
    }
    
    fmt.Println("Result:", string(buf))
}

每个循环迭代都将新的格式化内容追加到切片。最终结果按顺序包含所有追加的字符串。

追加不同数据类型

fmt.Appendf 通过格式动词处理各种数据类型。本示例演示了在一次追加中格式化不同类型。

data_types.go
package main

import (
    "fmt"
    "time"
)

func main() {
    buf := []byte("Current status: ")
    
    now := time.Now()
    active := true
    count := 42
    
    buf = fmt.Appendf(buf, "Active: %t, Count: %d, Time: %v", 
        active, count, now)
    
    fmt.Println(string(buf))
}

该示例展示了布尔值、整数和时间值的组合格式化。格式动词(%t、%d、%v)控制每个值的表示方式。

预分配切片容量

预分配切片容量可以提高 fmt.Appendf 的性能。本示例演示了重复追加的容量优化。

preallocate.go
package main

import (
    "fmt"
)

func main() {
    // Preallocate slice with 0 length but 256 capacity
    buf := make([]byte, 0, 256)
    
    for i := 0; i < 10; i++ {
        buf = fmt.Appendf(buf, "Number %04d\n", i)
    }
    
    fmt.Print(string(buf))
}

预分配的容量可以防止在追加过程中进行多次分配。当最终大小大致已知时,这尤其有益。

追加到现有字符串

fmt.Appendf 通过将字符串转换为字节切片来高效地扩展现有字符串。本示例展示了字符串扩展的实际应用。

extend_string.go
package main

import (
    "fmt"
)

func main() {
    greeting := "Hello"
    buf := []byte(greeting)
    
    name := "Bob"
    buf = fmt.Appendf(buf, ", %s! How are you?", name)
    
    fmt.Println(string(buf))
}

该示例从一个字符串开始,将其转换为字节,然后追加更多内容。这避免了创建中间字符串分配。

使用 Appendf 进行自定义格式化

fmt.Appendf 支持所有标准格式说明符。本示例演示了高级格式化选项。

custom_formatting.go
package main

import (
    "fmt"
    "math"
)

func main() {
    buf := []byte("Math results:\n")
    
    pi := math.Pi
    buf = fmt.Appendf(buf, "Pi: %.4f\n", pi)
    
    hex := 255
    buf = fmt.Appendf(buf, "Hex: %#x\n", hex)
    
    sci := 123456789.0
    buf = fmt.Appendf(buf, "Scientific: %e\n", sci)
    
    fmt.Println(string(buf))
}

该示例展示了浮点精度、十六进制和科学计数法格式化。每次追加都使用不同的格式说明符。

与 Sprintf 的性能比较

本示例将 fmt.Appendffmt.Sprintf 进行比较,以展示字符串构建中的性能差异。

performance.go
package main

import (
    "fmt"
    "time"
)

func buildWithSprintf(n int) string {
    var s string
    for i := 0; i < n; i++ {
        s += fmt.Sprintf("%d ", i)
    }
    return s
}

func buildWithAppendf(n int) string {
    buf := make([]byte, 0, n*3) // Estimate 3 bytes per number
    for i := 0; i < n; i++ {
        buf = fmt.Appendf(buf, "%d ", i)
    }
    return string(buf)
}

func main() {
    const count = 10000
    
    start := time.Now()
    buildWithSprintf(count)
    sprintfTime := time.Since(start)
    
    start = time.Now()
    buildWithAppendf(count)
    appendfTime := time.Since(start)
    
    fmt.Printf("Sprintf: %v\n", sprintfTime)
    fmt.Printf("Appendf: %v\n", appendfTime)
}

fmt.Appendf 对于增量字符串构建来说速度明显更快,尤其是在预分配容量的情况下。它避免了中间分配和复制。

来源

Go fmt 包文档

本教程通过实际的字符串格式化和追加示例,介绍了 Go 中的 fmt.Appendf 函数。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Golang 教程