Formatting strings


Yes, writing a format function is the easiest way to go and also the most flexible.

// as method of Square, see the link above if you want a freestanding function
pub fn format(
    self: Square,
    comptime _: []const u8,
    _: std.fmt.FormatOptions,
    writer: anytype,
) !void {
    const x: u8 = square_x(square);
    const y: u8 = square_y(square);
    try writer.print("{c}{d}", .{x + 'a', y + 1});
}

In a context where I would rather use some default string then have to handle some error I use std.fmt.allocPrint (confusingly named because it formats, doesn’t print anything) like this:

var buffer: [4096]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();

const str = std.fmt.allocPrint(allocator, "{d}", .{id}) catch "<buffer too small>";
// do something with it
fba.reset();
// allocate something else ...

I think the only way is to read the documentation, or look how it is used in a ducktyping manner. For writer normally a std.io.Writer or std.io.AnyWriter is expected or something that has these functions, but technically what ever works and has the functions that are used.

You shouldn’t use bufPrint because you would return temporary memory.
You shouldn’t use unreachable because of this unreachable - error discarding misuse you could catch and return some default string, or catch and panic.

The returning a default string only works well if you use something like a FixedBufferAllocator or an arena, because with that you don’t have to free the allocations individually, which means using something like catch "<buffer too small>" won’t error because nobody will try to call free for that string literal.

1 Like