I’m confused by what you’re trying to achieve here and what the problem actually is.
Is the issue that you’re attempting to initialize a std.ArrayList() inline as a parameter to this function? If you don’t need dynamic resizing of the slice of strings, you can just store and receive a []const []const u8, and pass it in like &.{"one", "two", "three", ...}. Alternatively, you can still pass it in as a static slice, initialize a std.ArrayList() and then calling .appendSlice() on it with the slice you’ve just received – this copies (and duplicates) memory but I suppose it’s not a big concern with these small sizes you’re handling from the above example.
If instead you have a pre-owned, dynamically-allocated slice, then I suppose you could still pass in a slice and take ownership of it with std.ArrayList(...).fromOwnedSlice() in your initializer, though note that this requires also passing in the allocator that was used to dynamically allocate this slice. If you want to transfer ownership of an already existing std.ArrayList(), you can pair this with std.ArrayList(...).toOwnedSlice() which is essentially the inverse operation.
Well, I just tried to help the author with passing an instance of ArrayList([]const u8) as a parameter, and did not think much about initializing as you noted.
The problem is that https://ziglang.org/documentation/0.10.0/std/#root;ArrayList.fromOwnedSlice
is empty, https://ziglang.org/documentation/0.10.0/std/#root;ArrayList.toOwnedSlice is empty too.
Using these two functions (how, when, why) is not obvious at all.
Basically, but I was thinking of the case where the caller already has a std.ArrayList() at hand, and you want to pass it in to the initialization of a struct that also wants to hold a std.ArrayList() and it’s fine to duplicate their contents, so:
const Menu = struct {
allocator: ...,
arrayList: std.ArrayList(T),
pub fn init(allocator: ..., items: []const []const T) !@This() {
var a = std.ArrayList(T).init(allocator);
try a.appendSlice(items);
return .{
.allocator = allocator,
.arrayList = a,
};
}
};
pub fn main() !void {
// ...
var a = std.ArrayList(T).init(allocator);
defer a.deinit();
try a.append(blargh);
try a.append(blorgh);
try a.append(blirgh);
const m = try Menu.init(allocator, a.items);
defer m.deinit();
// ...
}
Basically, pass around a slice still (via the .items field of the std.ArrayList()) and duplicate its contents.
Well, ownership is not unique to Rust, Rust gives an interesting twist by making the knowledge about the ownership of the various items explicit to the programmer and the compiler, as opposed to just the programmer. I’ve seen countless times something like this in a large C++ codebase:
class Thing {
public:
Thing( ... );
private:
AnotherThing* another_thing; // owned <-- this is a load-bearing comment :P
};
In Zig we don’t have a borrow checker or explicit ownership, so you need to be careful. But it’s so much easier than in C/C++: whenever something needs to allocate memory, you’ll see an allocator being passed around, so you know you’ll have to .deinit() accordingly later. Transfering ownership with fromOwnedSlice() / toOwnedSlice() is the exceptional case here, but the naming makes it clear who transfers ownership and who takes ownership of the data.
As for the lack of documentation: yes, autodoc is still being worked on. Until then, your best friend is the stdlib source code (which is not scary at all! it reads very clearly). See the code for fromOwnedSlice() and for toOwnedSlice().
I did similar things in C, so Zig’s approach is perfect for me. I had simple free list allocator (with malloc() backend) and used it for some linked list implementation - it performed ~3x faster than malloc() based list. Sorry for off-topic
thank you, I like it, because I think of my code generator at the same time as I rewrite my code from Nim-lang and from time to time, I stumble, because I would not like to sink into algorithmic delusions. And at the same time I learn the grammar of Zig-lang