This code works (v0.13.0):
const std = @import("std");
const NoteEvent = struct {
pitch: u8,
velocity: u8,
note_position: f32,
duration: f32,
pub fn debugPrint(self: @This()) void {
std.debug.print("NoteEvent{{ .pitch = {[pitch]}, .velocity: {[velocity]}, .note_position: {[note_position]}, .duration: {[duration]} }}\n", self);
}
};
const Measure = struct {
notes: []const NoteEvent, // added const here
};
const Track = struct {
name: []const u8, // added const here
measures: []const Measure, // added const here
};
const SongSection = struct {
tempo: u32 = 120,
time_signature: [2]u8 = .{ 4, 4 },
tracks: []const Track, // added const here
pub fn getMeasureDurationMs(self: SongSection) u32 { // removed * here
return self.time_signature[0] * self.getBeatDurationMs();
}
pub fn getBeatDurationMs(self: SongSection) u32 { // removed * here
return 60000 / self.tempo;
}
};
fn printNotes(notes: []const NoteEvent) void {
for (notes) |note| note.debugPrint();
}
fn printMeasure(measure: Measure) void {
printNotes(measure.notes);
}
pub fn main() !void {
const notes = [_]NoteEvent{
.{ .pitch = 60, .velocity = 127, .note_position = 0, .duration = 1 },
.{ .pitch = 62, .velocity = 127, .note_position = 1, .duration = 3 },
};
printNotes(¬es);
// this works:
const measure = Measure{ .notes = ¬es };
printMeasure(measure);
// this too :)
const measure2 = Measure{
.notes = &.{
.{ .pitch = 60, .velocity = 127, .note_position = 0, .duration = 1 },
.{ .pitch = 62, .velocity = 127, .note_position = 1, .duration = 3 },
},
};
printMeasure(measure2);
}
I think the big lesson here (as I’ve seen recommended by many others) is to always start out with const
and if you get an error because you need mutability, then make it non-const. As you can see, by just making all those slices and function parameters const
, all the errors went away and you can create slices from literals (as in measure2
) since literals are always const.
Always keep in mind, you can go from non-const to const safely with no problems, so you could pass in that slice from ArrayList
as you mentioned. Going from const to non-const, however, is unsafe (that’s why it requries an explicit @constCast
) and thus will make your functions and struct fields more restrictive instead of more general.