The idiomatic way of implementing custom formatting would be to implement a format
function. std.fmt.format
, which std.debug.print
and other formatting functions that take a format string with placeholders are derived from, has this to say in its doc comment:
If a formatted user type contains a function of the type
pub fn format( value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) !void
with
?
being the type formatted, this function will be called instead of the default implementation. This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
This means that if your struct implements a format
function, you can print it simply by passing it to a print function, like std.debug.print("{}", .{mat})
. See std.SemanticVersion.format
for one example of such a function.
A port of your original function would look something like this (writer
is assumed to be a std.io.Writer
):
pub fn format(
mat: Matrix,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = fmt;
_ = options;
try writer.writeAll(@typeName(Matrix));
try writer.writeAll("[\n");
for (0..rows) |ridx| {
try writer.writeAll("\t[");
for (0..cols) |cidx| {
try writer.print("{any}", .{mat.get(ridx, cidx)});
if (cidx != cols - 1) {
try writer.writeByte(',');
}
}
try writer.writeByte(']');
if (ridx != rows - 1) {
try writer.writeAll(",\n");
}
}
try writer.writeAll("]\n");
}
The format
function doesn’t allocate unless the writer
implementation allocates.
Addendum: If you don’t control the struct you want to format, you can implement a function that returns a std.fmt.Formatter
. See std.zig.fmtId
for an example.