Golang fmt.Appendf 函数
最后修改时间 2025 年 5 月 8 日
本教程将解释如何在 Go 中使用 fmt.Appendf 函数。我们将通过实际示例介绍高效的字符串操作,涵盖字符串格式化的基础知识。
fmt.Appendf 函数根据格式说明符进行格式化,并将结果追加到字节切片。在构建字符串时,它比 fmt.Sprintf 更高效。
在 Go 1.19+ 中,fmt.Appendf 提供了一种通过重用已分配内存来构建字符串的高效方法。当追加到具有足够容量的现有切片时,它可以避免分配。
fmt.Appendf 基本示例
fmt.Appendf 最简单的用法是将格式化的文本追加到字节切片。本示例演示了基本的字符串格式化和追加。
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 可以对同一个切片调用多次。本示例展示了通过多次追加进行增量字符串构建。
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 通过格式动词处理各种数据类型。本示例演示了在一次追加中格式化不同类型。
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 的性能。本示例演示了重复追加的容量优化。
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 通过将字符串转换为字节切片来高效地扩展现有字符串。本示例展示了字符串扩展的实际应用。
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 支持所有标准格式说明符。本示例演示了高级格式化选项。
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.Appendf 与 fmt.Sprintf 进行比较,以展示字符串构建中的性能差异。
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.Appendf 函数。