One pattern that seems to fall out of my brain when I return to Zig is having a struct with one array field that I want to assign to later. For example:
const StateData = struct {
// I realize this is wrong, this is what my brain always wants to try first
order: []burger=undefined,
};
const state:StateData = .{};
...
main(){
//...
state.order = _build_order(param1, param2);
//...
}
The problems with this are:
- if its a global scope, it needs to be compile time known
- even if it is in main, it needs to be initialized to something before being created
The solution is:
- use a 0 size array initialization
- ...or use an optional
In this case, because an optional would impact all the places that touch this variable, and it naturally falls into something that is iterated over, a 0 size intializiation works well for me.
const std = @import("std");
var raw = std.heap.GeneralPurposeAllocator(.{}){};
pub const ALLOCATOR = raw.allocator();
const Burger = struct {
num_toppings:i16,
};
const Order = struct {
contents: []Burger,
pub fn init(num_burgers: i32) Order {
var result_order = std.ArrayList(Burger).init(ALLOCATOR);
result_order.resize(num_burgers);
var ind:i16 = 0;
while (ind < num_burgers) : (ind += 1) {
result_order.append( .{ .num_toppings = ind }) catch unreachable;
}
return .{
.contents = result_order.items
};
}
};
const StateData = struct {
// one line:
// order: Order = .{ .contents = std.ArrayList(Burger).init(ALLOCATOR).items },
order: Order = Order.init(0),
other_state_data: i32 = 12,
more_state_data: f32 = 3.14159,
};
var state:StateData = .{};
pub fn main() void {
std.debug.print("order has {} burgers in it\n", .{ state.order.contents.len });
// make a new "order" later in runtime
state.order = Order.init(12);
std.debug.print("order has {} burgers in it\n", .{ state.order.contents.len });
}
Once again, thanks to the helpful and friendly zig community on discord!