Я в курсе, что Zig пока не идеален для любителей, но все же я пытался написать простенькую консольную программу, которая спрашивает у пользователя его имя, потом фамилию и в конце печатает "Your name is x и твоя фамилия y", просто чтобы посмотреть, смогу ли я.
Я придумал это в основном путем копирования и вставки примеров:
const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
const stdin = std.io.getStdIn().reader();
var buf: [100]u8 = undefined;
print("What's your first name? ", .{});
var fname = (try stdin.readUntilDelimiterOrEof(buf[0..], '\n')).?;
print("What's your last name? ", .{});
var lname = (try stdin.readUntilDelimiterOrEof(buf[0..], '\n')).?;
print("Your first name is {s} and your last name is {s}\n", .{fname, lname});
}
Теперь это компилируется, но не делает то, что я думал. Это связано с тем, что readUntilDelimiterOrEof() возвращает срез, поэтому второй вызов перезаписывает содержимое переменной fname.
Я могу создать переменную pos, которая отслеживает положение в буфере (например, fname.len), а затем сохранить следующий ввод в buf[pos..] вместо buf[0..], но это неуклюже, и я не Не думаю, что это то, что должен делать буфер.
Вместо этого я пытаюсь заставить fname и lname содержать свои копии среза в некоторой форме (массив?) и сохранять каждый пользовательский ввод в buf[0..], но без особого успеха. Я прочитал пару предложений. Присвоение новой переменной с помощью fname[0..(fname.len)].* не компилируется. Он работает только с числовым литералом, скажем, fname[0..5].*. std.mem.copy работает с (fname.len), но строка, похоже, не завершается нулем, потому что печать в конце программы печатает имя, а затем вопросительные знаки до размера, назначенного этой новой переменной .
Каков был бы разумный, идиоматический способ реализации этой элементарной программы? Спасибо.



Использование распределителя было бы более идиоматично:
const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
// It can be any allocator, not just FBA
var buffer: [128]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
const stdin = std.io.getStdIn().reader();
const max_size = 16;
print("What's your first name? ", .{});
var fname = (try stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', max_size)).?;
defer allocator.free(fname);
print("What's your last name? ", .{});
var lname = (try stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', max_size)).?;
defer allocator.free(lname);
print("Your first name is {s} and your last name is {s}\n", .{fname, lname});
}
Тем не менее, ваша попытка не так уж плоха и имеет свое применение. Вы можете исправить это, определив буфер как слайс и обновляя его каждый раз, когда вы что-то в него записываете:
var memory: [100]u8 = undefined;
var buffer: []u8 = &memory;
print("What's your first name? ", .{});
var fname = (try stdin.readUntilDelimiterOrEof(buffer, '\n')).?;
buffer = buffer[fname.len..];
print("What's your last name? ", .{});
var lname = (try stdin.readUntilDelimiterOrEof(buffer, '\n')).?;
buffer = buffer[lname.len..];
print("Your first name is {s} and your last name is {s}\n", .{fname, lname});