Hi!
I’m in a situation in which a basic try-catch block would be very handy.
I want to check that the user entered 2 arguments via the command line, and show a message and return error otherwise.
In C, this would be very easy, I would do:
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: %s <source> <dest>\n", argv[0]);
return 1;
}
}
I’m stuggling to do the same in Zig.
Right now I have the following:
pub fn main() !void {
var args = std.process.args();
const bin: []const u8 = args.next().?;
const source_path: []const u8 = args.next() orelse return error.InvalidArguments;
const dest_path: []const u8 = args.next() orelse return error.InvalidArguments;
if (args.skip()) return error.InvalidArguments;
print("bin: {s}\n", .{bin});
print("source: {s}\n", .{source_path});
print("dest: {s}\n", .{dest_path});
}
I would like to be able print a message to the user and return an error if any of the lines above with the return error.InvalidArguments
fail.
How do I do that in Zig?
You can use a labeled block together with break :label error.Error
to get something similar to a try-catch block:
const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
// Side note: 'std.process.args' is not portable and won't work on Windows
var args = try std.process.argsWithAllocator(std.heap.page_allocator);
defer args.deinit();
const bin: []const u8 = args.next().?;
const source_path: []const u8, const dest_path: []const u8 = read_args: {
const source = args.next() orelse break :read_args error.InvalidArguments;
const dest = args.next() orelse break :read_args error.InvalidArguments;
if (args.skip()) break :read_args error.InvalidArguments;
break :read_args .{ source, dest };
} catch |err| {
print("Usage: {s} <source> <dest>\n", .{bin});
return err;
};
print("bin: {s}\n", .{bin});
print("source: {s}\n", .{source_path});
print("dest: {s}\n", .{dest_path});
}
This example uses tuple destructuring which I believe is only available on the master branch of the compiler. If you prefer and you could also declare mutable variables outside of the block and assign them inside:
const bin: []const u8 = args.next().?;
var source_path: []const u8 = undefined;
var dest_path: []const u8 = undefined;
(read_args: {
source_path = args.next() orelse break :read_args error.InvalidArguments;
dest_path = args.next() orelse break :read_args error.InvalidArguments;
if (args.skip()) break :read_args error.InvalidArguments;
} catch |err| {
print("Usage: {s} <source> <dest>\n", .{bin});
return err;
});
Here the parentheses are necessary for the compiler to parse the block as an expression and not a statement.
7 Likes
That’s exactly what I was looking for! Thank you very much!