ZetCode

Golang fmt.Appendf function

last modified May 8, 2025

This tutorial explains how to use the fmt.Appendf function in Go. We'll cover string formatting basics with practical examples of efficient string manipulation.

The fmt.Appendf function formats according to a format specifier and appends the result to a byte slice. It's more efficient than fmt.Sprintf when building strings incrementally.

In Go 1.19+, fmt.Appendf provides a performant way to build strings by reusing allocated memory. It avoids allocations when appending to existing slices with sufficient capacity.

Basic fmt.Appendf example

The simplest use of fmt.Appendf appends formatted text to a byte slice. This example demonstrates basic string formatting and appending.

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))
}

The code starts with an initial byte slice and appends formatted content. The output combines the original and new content in a single string.

Appending multiple times

fmt.Appendf can be called multiple times on the same slice. This example shows incremental string building with multiple appends.

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))
}

Each loop iteration appends new formatted content to the slice. The final result contains all appended strings in sequence.

Appending different data types

fmt.Appendf handles various data types through format verbs. This example demonstrates formatting different types in a single append.

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))
}

The example shows boolean, integer, and time values formatted together. The format verbs (%t, %d, %v) control how each value is represented.

Preallocating slice capacity

Preallocating slice capacity improves performance with fmt.Appendf. This example demonstrates capacity optimization for repeated appends.

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))
}

The preallocated capacity prevents multiple allocations during appends. This is especially beneficial when the final size is approximately known.

Appending to existing strings

fmt.Appendf efficiently extends existing strings by converting them to byte slices. This example shows string extension in practice.

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))
}

The example starts with a string, converts it to bytes, then appends more content. This avoids creating intermediate string allocations.

Custom formatting with Appendf

fmt.Appendf supports all standard format specifiers. This example demonstrates advanced formatting options.

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))
}

The example shows floating-point precision, hexadecimal, and scientific notation formatting. Each append uses a different format specifier.

Performance comparison with Sprintf

This example compares fmt.Appendf with fmt.Sprintf to demonstrate performance differences in string building.

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 is significantly faster for incremental string building, especially with preallocated capacity. It avoids intermediate allocations and copying.

Source

Go fmt package documentation

This tutorial covered the fmt.Appendf function in Go with practical examples of efficient string formatting and appending.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Golang tutorials.