ZetCode

Golang strconv.AppendFloat

最后修改于 2025 年 4 月 20 日

本教程将解释如何在 Go 中使用 strconv.AppendFloat 函数。我们将通过实际示例介绍浮点数到字符串转换的基础知识。

strconv.AppendFloat 函数将浮点数转换为字符串并将其附加到字节切片。它提供对格式的精确控制。

AppendFloat 对于构建包含浮点数值的字符串非常高效,因为它通过直接附加到现有字节切片来避免分配。它支持各种格式选项和精度。

基本的 strconv.AppendFloat 示例

strconv.AppendFloat 最简单的用法是将浮点数转换为字符串并将其附加到字节切片。这里我们展示了基本用法。

basic_appendfloat.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    buf := []byte("Value: ")
    f := 3.14159
    
    buf = strconv.AppendFloat(buf, f, 'f', 2, 64)
    
    fmt.Println(string(buf))
}

我们从包含 "Value: " 的字节切片开始,然后附加一个格式化的浮点数。'f' 格式指定了定点表示法,并带有 2 位小数。

不同的格式选项

strconv.AppendFloat 支持多种格式选项。此示例演示了 'f'、'e'、'g' 和 'b' 格式。

formats.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    f := 1234.5678
    
    fmt.Println(string(strconv.AppendFloat([]byte{}, f, 'f', 2, 64)))
    fmt.Println(string(strconv.AppendFloat([]byte{}, f, 'e', 2, 64)))
    fmt.Println(string(strconv.AppendFloat([]byte{}, f, 'g', 4, 64)))
    fmt.Println(string(strconv.AppendFloat([]byte{}, f, 'b', -1, 64)))
}

每种格式会产生不同的输出:'f' 用于定点数,'e' 用于科学计数法,'g' 用于紧凑表示,'b' 用于二进制指数。

控制精度

精度参数控制显示多少位数。此示例显示了同一浮点数的不同精度值。

precision.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    f := 3.141592653589793
    
    for _, prec := range []int{0, 2, 4, 6, 8} {
        buf := strconv.AppendFloat([]byte("π ≈ "), f, 'f', prec, 64)
        fmt.Println(string(buf))
    }
}

我们以递增的精度级别展示 π。更高的精度值会在输出中显示更多的小数位数。

构建复杂字符串

AppendFloat 有助于高效地构建复杂字符串。此示例创建了一个格式化的测量字符串。

complex_string.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    temp := 23.456
    humidity := 45.678
    
    buf := []byte("Current conditions: ")
    buf = strconv.AppendFloat(buf, temp, 'f', 1, 64)
    buf = append(buf, "°C, "...)
    buf = strconv.AppendFloat(buf, humidity, 'f', 1, 64)
    buf = append(buf, "% humidity"...)
    
    fmt.Println(string(buf))
}

我们通过附加多个浮点数值和文本来构建天气报告字符串。与字符串拼接相比,这种方法可以最大限度地减少分配。

处理特殊的浮点数值

AppendFloat 可以正确处理 NaN 和无穷大等特殊浮点数值。此示例演示了它们的字符串表示。

special_values.go
package main

import (
    "fmt"
    "math"
    "strconv"
)

func main() {
    values := []float64{
        math.NaN(),
        math.Inf(1),
        math.Inf(-1),
        0.0,
    }
    
    for _, v := range values {
        buf := strconv.AppendFloat([]byte{}, v, 'g', -1, 64)
        fmt.Println(string(buf))
    }
}

特殊浮点数值会被转换为它们的字符串表示:“NaN”表示非数字,“+Inf”表示正无穷大,“-Inf”表示负无穷大。

性能比较

此示例比较了 AppendFloatfmt.Sprintf 在浮点数到字符串转换性能上的差异。

performance.go
package main

import (
    "fmt"
    "strconv"
    "time"
)

func main() {
    const iterations = 1000000
    f := 123.456789
    
    // Benchmark AppendFloat
    start := time.Now()
    buf := make([]byte, 0, 32)
    for i := 0; i < iterations; i++ {
        buf = strconv.AppendFloat(buf[:0], f, 'f', 2, 64)
    }
    fmt.Println("AppendFloat duration:", time.Since(start))
    
    // Benchmark Sprintf
    start = time.Now()
    for i := 0; i < iterations; i++ {
        _ = fmt.Sprintf("%.2f", f)
    }
    fmt.Println("Sprintf duration:", time.Since(start))
}

AppendFloat 在浮点数格式化方面比 fmt.Sprintf 快得多,尤其是在性能关键的代码中构建字符串时。

实际示例:CSV 生成

这个实际示例演示了如何使用 AppendFloat 高效地生成包含浮点数值的 CSV 数据。

csv_generation.go
package main

import (
    "fmt"
    "strconv"
)

type Measurement struct {
    Time  float64
    Value float64
}

func main() {
    data := []Measurement{
        {0.0, 12.3},
        {1.0, 15.6},
        {2.0, 18.2},
        {3.0, 22.1},
    }
    
    var csv []byte
    csv = append(csv, "time,value\n"...)
    
    for _, m := range data {
        csv = strconv.AppendFloat(csv, m.Time, 'f', 1, 64)
        csv = append(csv, ',')
        csv = strconv.AppendFloat(csv, m.Value, 'f', 1, 64)
        csv = append(csv, '\n')
    }
    
    fmt.Println(string(csv))
}

我们通过将浮点数值直接附加到字节切片来生成 CSV 输出。这种方法在内存方面效率很高,并避免了不必要的字符串分配。

来源

Go strconv 包文档

本教程通过各种场景下的浮点数到字符串转换的实际示例,涵盖了 Go 中的 strconv.AppendFloat 函数。

作者

我叫 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Go 教程