Converting to Strings - Format Functions 4/7

When you’re working with Go, you’ll frequently need to convert various data types into their string representations. The strconv
package provides a collection of Format functions that handle this conversion efficiently and give you fine-grained control over the output format.
FormatBool: Converting Boolean Values
The FormatBool
function converts a boolean value to its string representation. It’s straightforward - true becomes “true” and false becomes “false”.
package main
import (
"fmt"
"strconv"
)
func main() {
isActive := true
isComplete := false
activeStr := strconv.FormatBool(isActive)
completeStr := strconv.FormatBool(isComplete)
fmt.Println("Active:", activeStr) // Output: Active: true
fmt.Println("Complete:", completeStr) // Output: Complete: false
}
This function is particularly useful when building configuration strings, JSON responses, or any scenario where you need boolean values as text. Unlike manual string concatenation or fmt.Sprintf, FormatBool is optimized for this specific conversion.
// Building a query string
enabled := true
url := "https://api.example.com/data?enabled=" + strconv.FormatBool(enabled)
fmt.Println(url) // Output: https://api.example.com/data?enabled=true
The function handles the conversion without any formatting options - it’s a simple true/false mapping that’s consistent and predictable across your application.
FormatInt: Converting Signed Integers with Base Options
The FormatInt
function converts a signed 64-bit integer to its string representation in any base from 2 to 36. This gives you flexibility for different numbering systems and formatting requirements.
package main
import (
"fmt"
"strconv"
)
func main() {
number := int64(42)
// Convert to different bases
binary := strconv.FormatInt(number, 2)
decimal := strconv.FormatInt(number, 10)
hexadecimal := strconv.FormatInt(number, 16)
fmt.Println("Binary:", binary) // Output: Binary: 101010
fmt.Println("Decimal:", decimal) // Output: Decimal: 42
fmt.Println("Hex:", hexadecimal) // Output: Hex: 2a
}
Base conversion is particularly useful when working with different numbering systems or when you need to display numbers in specific formats:
// Working with file permissions
permission := int64(0o755) // octal literal
octal := strconv.FormatInt(permission, 8)
fmt.Printf("File permission: %s (octal)\n", octal) // Output: File permission: 755 (octal)
// Converting to base 36 for compact representation
id := int64(123456789)
compactID := strconv.FormatInt(id, 36)
fmt.Printf("Compact ID: %s\n", compactID) // Output: Compact ID: 21i3v9
The function handles negative numbers correctly, maintaining the sign in the converted string:
negative := int64(-255)
negBinary := strconv.FormatInt(negative, 2)
negHex := strconv.FormatInt(negative, 16)
fmt.Println("Negative binary:", negBinary) // Output: Negative binary: -11111111
fmt.Println("Negative hex:", negHex) // Output: Negative hex: -ff
When working with regular int types instead of int64, you need to cast them:
regularInt := 1000
result := strconv.FormatInt(int64(regularInt), 10)
fmt.Println(result) // Output: 1000
FormatUint: Converting Unsigned Integers
The FormatUint
function works similarly to FormatInt but specifically handles unsigned 64-bit integers. Since unsigned integers can’t be negative, this function is optimized for positive values and can represent larger numbers than their signed counterparts.
package main
import (
"fmt"
"strconv"
)
func main() {
number := uint64(255)
// Convert to different bases
binary := strconv.FormatUint(number, 2)
decimal := strconv.FormatUint(number, 10)
hexadecimal := strconv.FormatUint(number, 16)
fmt.Println("Binary:", binary) // Output: Binary: 11111111
fmt.Println("Decimal:", decimal) // Output: Decimal: 255
fmt.Println("Hex:", hexadecimal) // Output: Hex: ff
}
This function shines when working with large numbers that exceed the range of signed integers:
// Working with large unsigned values
maxUint64 := uint64(18446744073709551615) // Maximum uint64 value
maxStr := strconv.FormatUint(maxUint64, 10)
fmt.Println("Max uint64:", maxStr) // Output: Max uint64: 18446744073709551615
// Converting to hex for memory addresses or IDs
memoryAddr := uint64(0xDEADBEEF)
addrStr := strconv.FormatUint(memoryAddr, 16)
fmt.Printf("Memory address: 0x%s\n", addrStr) // Output: Memory address: 0xdeadbeef
Common use cases include working with timestamps, file sizes, or system identifiers:
// Unix timestamp
timestamp := uint64(1609459200) // January 1, 2021
timestampStr := strconv.FormatUint(timestamp, 10)
fmt.Println("Timestamp:", timestampStr) // Output: Timestamp: 1609459200
// File size in bytes
fileSize := uint64(2147483648) // 2GB in bytes
sizeStr := strconv.FormatUint(fileSize, 10)
fmt.Printf("File size: %s bytes\n", sizeStr) // Output: File size: 2147483648 bytes
When converting from smaller unsigned integer types, you still need to cast to uint64:
smallUint := uint32(1000)
result := strconv.FormatUint(uint64(smallUint), 10)
fmt.Println(result) // Output: 1000
FormatFloat: Precision Control for Floating-Point Numbers
The FormatFloat
function provides comprehensive control over how floating-point numbers are converted to strings. It accepts four parameters: the float64 value, format specifier, precision, and bit size.
package main
import (
"fmt"
"strconv"
)
func main() {
number := 3.14159265359
// Different format specifiers
scientific := strconv.FormatFloat(number, 'e', 2, 64)
fixed := strconv.FormatFloat(number, 'f', 2, 64)
general := strconv.FormatFloat(number, 'g', 2, 64)
fmt.Println("Scientific:", scientific) // Output: Scientific: 3.14e+00
fmt.Println("Fixed:", fixed) // Output: Fixed: 3.14
fmt.Println("General:", general) // Output: General: 3.1
}
The format specifiers determine how the number is represented:
value := 1234.5678
// 'f' - fixed-point notation
fixed1 := strconv.FormatFloat(value, 'f', 1, 64)
fixed4 := strconv.FormatFloat(value, 'f', 4, 64)
fmt.Println("Fixed 1 decimal:", fixed1) // Output: Fixed 1 decimal: 1234.6
fmt.Println("Fixed 4 decimal:", fixed4) // Output: Fixed 4 decimal: 1234.5678
// 'e' - scientific notation (lowercase)
scientific := strconv.FormatFloat(value, 'e', 2, 64)
fmt.Println("Scientific:", scientific) // Output: Scientific: 1.23e+03
// 'E' - scientific notation (uppercase)
scientificUpper := strconv.FormatFloat(value, 'E', 2, 64)
fmt.Println("Scientific upper:", scientificUpper) // Output: Scientific upper: 1.23E+03
The precision parameter controls decimal places or significant digits depending on the format:
pi := 3.14159265359
// With 'f' format, precision means decimal places
fmt.Println(strconv.FormatFloat(pi, 'f', 0, 64)) // Output: 3
fmt.Println(strconv.FormatFloat(pi, 'f', 3, 64)) // Output: 3.142
fmt.Println(strconv.FormatFloat(pi, 'f', 6, 64)) // Output: 3.141593
// With 'g' format, precision means significant digits
fmt.Println(strconv.FormatFloat(pi, 'g', 3, 64)) // Output: 3.14
fmt.Println(strconv.FormatFloat(pi, 'g', 5, 64)) // Output: 3.1416
Special precision value -1 uses the smallest number of digits necessary:
values := []float64{1.0, 1.5, 1.25, 1.125}
for _, v := range values {
result := strconv.FormatFloat(v, 'f', -1, 64)
fmt.Printf("%.3f -> %s\n", v, result)
}
// Output:
// 1.000 -> 1
// 1.500 -> 1.5
// 1.250 -> 1.25
// 1.125 -> 1.125
The bit size parameter (32 or 64) affects rounding behavior for float32 values:
// Converting float32 with proper bit size
var f32 float32 = 1.23456789
str32 := strconv.FormatFloat(float64(f32), 'f', -1, 32)
str64 := strconv.FormatFloat(float64(f32), 'f', -1, 64)
fmt.Println("As float32:", str32) // Output: As float32: 1.2345679
fmt.Println("As float64:", str64) // Output: As float64: 1.2345678806304932
FormatComplex: Handling Complex Number Formatting
The FormatComplex
function converts complex numbers to their string representation using a format similar to FormatFloat. It takes a complex128 value, format specifier, precision, and bit size, applying the formatting rules to both the real and imaginary components.
package main
import (
"fmt"
"strconv"
)
func main() {
c := complex(3.14159, 2.71828)
// Different format specifiers
fixed := strconv.FormatComplex(c, 'f', 2, 128)
scientific := strconv.FormatComplex(c, 'e', 2, 128)
general := strconv.FormatComplex(c, 'g', 3, 128)
fmt.Println("Fixed:", fixed) // Output: Fixed: (3.14+2.72i)
fmt.Println("Scientific:", scientific) // Output: Scientific: (3.14e+00+2.72e+00i)
fmt.Println("General:", general) // Output: General: (3.14+2.72i)
}
The function handles various complex number scenarios, including negative imaginary parts and zero components:
// Different complex number patterns
positive := complex(1.5, 2.5)
negativeIm := complex(1.5, -2.5)
realOnly := complex(5.0, 0)
imaginaryOnly := complex(0, 3.0)
fmt.Println(strconv.FormatComplex(positive, 'f', 1, 128)) // Output: (1.5+2.5i)
fmt.Println(strconv.FormatComplex(negativeIm, 'f', 1, 128)) // Output: (1.5-2.5i)
fmt.Println(strconv.FormatComplex(realOnly, 'f', 1, 128)) // Output: (5.0+0.0i)
fmt.Println(strconv.FormatComplex(imaginaryOnly, 'f', 1, 128)) // Output: (0.0+3.0i)
Precision control works the same way as FormatFloat, affecting both real and imaginary parts:
c := complex(3.14159265, 2.71828182)
// Different precision levels
fmt.Println(strconv.FormatComplex(c, 'f', 2, 128)) // Output: (3.14+2.72i)
fmt.Println(strconv.FormatComplex(c, 'f', 4, 128)) // Output: (3.1416+2.7183i)
fmt.Println(strconv.FormatComplex(c, 'f', -1, 128)) // Output: (3.14159265+2.71828182i)
When working with complex64 values, specify the appropriate bit size:
// Working with complex64
var c64 complex64 = complex(float32(1.23456), float32(7.89012))
str64 := strconv.FormatComplex(complex128(c64), 'f', -1, 64)
str128 := strconv.FormatComplex(complex128(c64), 'f', -1, 128)
fmt.Println("As complex64:", str64) // Output: As complex64: (1.23456+7.89012i)
fmt.Println("As complex128:", str128) // Output: As complex128: (1.2345600128173828+7.890120029449463i)
Scientific notation is particularly useful for complex numbers with large or small magnitudes:
largeComplex := complex(1.23e6, -4.56e-3)
smallComplex := complex(1.23e-6, 4.56e3)
large := strconv.FormatComplex(largeComplex, 'e', 2, 128)
small := strconv.FormatComplex(smallComplex, 'e', 2, 128)
fmt.Println("Large:", large) // Output: Large: (1.23e+06-4.56e-03i)
fmt.Println("Small:", small) // Output: Small: (1.23e-06+4.56e+03i)
This completes the comprehensive coverage of Go’s string formatting functions. Each function provides specific optimization and control for its respective data type, giving you the precision and format flexibility needed for professional applications.