I think, it’s even better to have both init
and create
“constructors”, like this:
const std = @import("std");
const Allocator = std.mem.Allocator;
const User = struct {
domain: []const u8 = "ziggit.dev",
enabled: bool = false,
fn init(d: []const u8, e: bool) User {
return .{.domain = d, .enabled = e};
}
fn create(a: Allocator, d: []const u8, e: bool) !*User {
var u = try a.create(User);
u.* = init(d, e);
return u;
}
};
pub fn main() !void {
const a = std.heap.c_allocator;
const u_on_stack = User.init("dom1.org", true);
const u_on_heap = try User.create(a, "dom2.org", true);
std.debug.print(
"user on stack : d = '{s}', e = {} ({*})\n",
.{u_on_stack.domain, u_on_stack.enabled, &u_on_stack}
);
std.debug.print(
"user on heap : d = '{s}', e = {} ({*})\n",
.{u_on_heap.domain, u_on_heap.enabled, u_on_heap}
);
}
Note: compile with zig build-exe aini.zig -lc
This way we can conveniently use either stack allocated objects or heap allocated objects, depending on whatever is needed at the moment.
Output of the program:
$ ./aini
user on stack : d = 'dom1.org', e = true (aini.User@7ffc6442dff0)
user on heap : d = 'dom2.org', e = true @aini.User@4892a0)