Formatting, Printing and I/O Interfaces

20.1 Format Specifiers

Default formatting for numbers and enums. Errors at compile time for types that need an explicit specifier in 0.15 String ([]const u8) Character (u8) Hex lowercase / uppercase Binary / octal Debug representation of any type Optional (null or the value) Call the type's format method (0.15) UTF-8 code point {B} / {Bi} Byte sizes (KB / KiB) Duration (nanoseconds)

{d:5}, {d:0>5}, {s:<10}, {s:^10}, {d:.2} (precision) {0} {1} {0}, {[name]s}

std.debug.print("{d:0>4} {x} {s:>8} {d:.3} {any} {?d}\n", .{ 7, 255, "hi", 3.14159, [_]u8{ 1, 2 }, @as(?i32, null) });

20.2 Custom Formatting (0.15 Style)

Before 0.15, format took (self, comptime fmt, options, writer: anytype) and was used with {}. Update old code accordingly.

const Point = struct {
    x: i32,
    y: i32,
    pub fn format(self: Point, writer: *std.Io.Writer) std.Io.Writer.Error!void {
        try writer.print("({d}, {d})", .{ self.x, self.y });
    }
};
std.debug.print("{f}\n", .{Point{ .x = 1, .y = 2 }});    // {f} invokes format

20.3 The std.Io.Writer and std.Io.Reader Interfaces (0.15)

0.15 replaced the generic anytype writers with concrete, buffered, non-generic interfaces: *std.Io.Writer and *std.Io.Reader. The buffer lives in the interface ("buffer in the interface"), which improves performance and reduces code bloat.

Reading stdin: std.fs.File.stdin().reader(&buf) then .interface.

Older code (≤ 0.14) used std.io.getStdOut().writer(), std.io.bufferedWriter, and reader.readUntilDelimiterOrEof. You'll see these in tutorials, so map them to the new API.

// Writing to a file
var buf: [4096]u8 = undefined;
var file_writer = file.writer(&buf);
const w = &file_writer.interface;
try w.print("value = {d}\n", .{42});
try w.writeAll("raw bytes\n");
try w.flush();

// Writing into memory
var allocating = std.Io.Writer.Allocating.init(allocator);
defer allocating.deinit();
try allocating.writer.print("{s}-{d}", .{ "id", 7 });
const result = allocating.written();
_ = result;
var fixed_buf: [64]u8 = undefined;
var fixed = std.Io.Writer.fixed(&fixed_buf);
try fixed.print("{d}", .{123});

// Reading
var rbuf: [4096]u8 = undefined;
var file_reader = file.reader(&rbuf);
const r = &file_reader.interface;
while (r.takeDelimiterExclusive('\n')) |line| {
    std.debug.print("{s}\n", .{line});
} else |err| switch (err) {
    error.EndOfStream => {},
    else => return err,
}