ZetCode

Golang fmt.Append 函数

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

本教程将讲解如何在 Go 中使用 fmt.Append 函数。我们将通过实际的字符串高效操作示例,涵盖字符串构建基础知识。

fmt.Append 函数用于通过将格式化数据附加到字节切片来高效地构建字符串。它在复杂的字符串构建操作中比字符串拼接具有性能优势。

在 Go 中,fmt.Append 是 fmt 包的一部分,并于 Go 1.19 引入。它的工作方式类似于 fmt.Printf,但写入的是字节切片而不是 io.Writer。

fmt.Append 基本示例

fmt.Append 最简单的用法是将格式化字符串附加到字节切片。此示例演示了基本的字符串附加操作。
注意: 该函数返回一个新的切片,它不会修改原始切片。

basic_append.go
package main

import (
    "fmt"
)

func main() {
    buf := []byte("Hello, ")
    buf = fmt.Append(buf, "World!")
    
    fmt.Println(string(buf)) // Convert back to string for printing
    
    // Append multiple values
    nums := []byte("Numbers: ")
    nums = fmt.Append(nums, 1, 2, 3)
    fmt.Println(string(nums))
}

该函数将格式化后的值附加到字节切片。原始切片可以是空的,也可以包含现有数据。

使用格式化动词进行附加

fmt.Append 支持与 fmt.Printf 相同的格式化动词。此示例展示了格式化数字的附加操作。

formatting_verbs.go
package main

import (
    "fmt"
)

func main() {
    buf := []byte("Formatted values: ")
    
    // Append with different format verbs
    buf = fmt.Appendf(buf, "Int: %d, Float: %.2f, Bool: %t", 42, 3.14159, true)
    
    fmt.Println(string(buf))
    
    // Hexadecimal example
    hexBuf := []byte("Hex: ")
    hexBuf = fmt.Appendf(hexBuf, "%x", 255)
    fmt.Println(string(hexBuf))
}

Appendf 变体允许对格式进行精确控制。格式化动词的用法与其他 fmt 包函数完全相同。

附加切片和数组

fmt.Append 可以附加整个切片和数组。此示例展示了如何有效地从集合构建字符串。

append_slices.go
package main

import (
    "fmt"
)

func main() {
    names := []string{"Alice", "Bob", "Charlie"}
    buf := []byte("Names: ")
    
    // Append each name with separator
    for _, name := range names {
        buf = fmt.Append(buf, name, ", ")
    }
    
    // Remove trailing comma and space
    if len(names) > 0 {
        buf = buf[:len(buf)-2]
    }
    
    fmt.Println(string(buf))
    
    // Alternative with fmt.Appendln
    buf = []byte("Names:\n")
    for _, name := range names {
        buf = fmt.Appendln(buf, name)
    }
    fmt.Println(string(buf))
}

该示例展示了两种方法:逗号分隔值和换行分隔。该函数会自动处理每个元素的字符串转换。

与 strings.Builder 的性能比较

在某些用例中,fmt.Append 可能比 strings.Builder 更高效。此示例比较了它们的性能特征。

performance_comparison.go
package main

import (
    "fmt"
    "strings"
    "time"
)

func buildWithBuilder(count int) string {
    var b strings.Builder
    for i := 0; i < count; i++ {
        fmt.Fprintf(&b, "Item %d, ", i)
    }
    return b.String()
}

func buildWithAppend(count int) string {
    buf := []byte{}
    for i := 0; i < count; i++ {
        buf = fmt.Append(buf, "Item ", i, ", ")
    }
    return string(buf)
}

func main() {
    const count = 10000
    
    start := time.Now()
    buildWithBuilder(count)
    builderTime := time.Since(start)
    
    start = time.Now()
    buildWithAppend(count)
    appendTime := time.Since(start)
    
    fmt.Printf("strings.Builder: %v\n", builderTime)
    fmt.Printf("fmt.Append: %v\n", appendTime)
}

性能差异取决于具体用例。fmt.Append 通常在许多小量附加操作中表现更优,而 strings.Builder 可能更适合少量、大批量的写入。

附加自定义类型

fmt.Append 可与实现 Stringer 接口的任何类型一起使用。此示例演示了自定义类型的附加操作。

custom_types.go
package main

import (
    "fmt"
)

type Point struct {
    X, Y int
}

func (p Point) String() string {
    return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}

func main() {
    buf := []byte("Points: ")
    
    p1 := Point{10, 20}
    p2 := Point{30, 40}
    
    buf = fmt.Append(buf, p1, " ", p2)
    fmt.Println(string(buf))
    
    // Works with pointers too
    buf = []byte("Pointer points: ")
    buf = fmt.Append(buf, &p1, " ", &p2)
    fmt.Println(string(buf))
}

在附加自定义类型时,会自动调用 String 方法。这为用户定义的数据结构提供了灵活的格式化。

fmt.Append 的错误处理

fmt.Append 不会返回错误,这使其比其他一些格式化函数更简单。此示例展示了无错误的使用模式。

error_handling.go
package main

import (
    "fmt"
)

func main() {
    // No error handling needed
    buf := []byte{}
    buf = fmt.Append(buf, "This", " ", "works", " ", 123)
    fmt.Println(string(buf))
    
    // Even with invalid format strings, it won't panic
    buf = []byte{}
    buf = fmt.Appendf(buf, "Value: %d", "not a number") // %d expects number
    fmt.Println(string(buf)) // Still produces output (with wrong format)
    
    // For critical formatting, validate first
    value := "not a number"
    if _, err := fmt.Sscanf(value, "%d", new(int)); err == nil {
        buf = fmt.Appendf(buf, "Valid number: %d", value)
    } else {
        buf = fmt.Append(buf, "Invalid number: ", value)
    }
    fmt.Println(string(buf))
}

虽然 fmt.Append 在格式不匹配时不会出现恐慌,但输出可能不如预期。对于关键格式,请先验证输入。

构建复杂字符串

fmt.Append 在增量构建复杂字符串方面表现出色。此示例展示了一个多步字符串构造。

complex_strings.go
package main

import (
    "fmt"
    "time"
)

func buildReport() []byte {
    buf := []byte("REPORT\n")
    buf = fmt.Appendf(buf, "Generated: %s\n\n", time.Now().Format(time.RFC1123))
    
    // Add header
    buf = fmt.Append(buf, "ITEM".padRight(20), "QUANTITY".padRight(10), "PRICE\n")
    buf = fmt.Append(buf, "----".padRight(20), "--------".padRight(10), "-----\n")
    
    // Add items
    items := []struct {
        name     string
        quantity int
        price    float64
    }{
        {"Widget", 5, 12.99},
        {"Gadget", 2, 29.95},
        {"Thingy", 10, 1.49},
    }
    
    for _, item := range items {
        buf = fmt.Appendf(buf, "%-20s%-10d$%.2f\n", 
            item.name, item.quantity, item.price)
    }
    
    // Add footer
    buf = fmt.Append(buf, "\nTotal items: ", len(items), "\n")
    return buf
}

func main() {
    report := buildReport()
    fmt.Println(string(report))
}

// Helper function for padding
func (s string) padRight(width int) string {
    if len(s) >= width {
        return s
    }
    return s + strings.Repeat(" ", width-len(s))
}

该示例演示了如何构建包含标题、数据行和页脚的格式化报告。fmt.Append 高效地处理了每个部分。

来源

Go fmt 包文档

本教程通过 Go 中 fmt.Append 函数的实际示例,讲解了高效的字符串构建和格式化。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已创作了超过 1,400 篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Golang 教程