So first I’m wondering: why can’t I create a slice like this? I know I can make it a const [] const []u8 as detailed in the answer How do I initialize a slice of slices in Zig?, but I think it’s reasonable to non-const slice (or whatever that’s called) sometimes. So second, I’m wondering: Is there a good way to initialize one of those?
The issue is string literals "asdlf" are const pointers, but you are asking for non const slices.
If you change words: [][]const u8, you will then find the same issue with the outer slice as well, since &.{} is a pointer to a literal it is also const.
If you do words: []const []const u8 it will work. Your next issue is your function requires non const slices.
To get non const slices, you need to allocate stable and mutable memory on either the heap or the stack:
test "returns number of words" {
// "asdf" is a pointer to an array
// so we can dereference it to copy the array to mutable memory
var hello = "hello".*;
var world = "world".*;
// must be an array to get mutable memory for the outer slice
var words: [2][]u8 = .{&hello, &world};
_ = count(&words); // coerce the array to a slice
}
I actually thing your first post got me there. It gave me just enough to (I think) go look up all the pieces. Let me see if my understanding is correct:
A string literal like "asdf" is known at compile time and therefore constant.
It’s also an array of values, in this case a 4 item array of u8 values.
I would say it’s constant because it’s a literal, but comptime values are also always constant (at runtime) so it doesn’t matter much.
The array is null terminated, not the pointer.
You can do this in any order, infact you can do it in one step.
Something worth knowing, is that &.{a, b} where a and b are var/const is not a literal. If a and b are comptime known, then it will also be comptime known and be put into global read only memory.
If a or b is runtime known, then it will also be runtime known. In which case it does take up some stack memory, but it still can’t be mutable for a variety of reasons:
to keep it consistent with literals and comptime values
to simplify the language both its implementation and semantics
it at least keeps mutable memory explicit
it facilitates more optimisations
In the case where it is runtime known, it is called a temporary.
For the comptime case, it’s just a comptime value.