Zig Tutorial — String
If you are confused of string or string literal in Zig, please read these two articles first: “What’s a String Literal in Zig?” and “Zig Newcomer Programming FAQs”. My understanding of Zig string may not be correct, but here is what I know so far.
First, Zig do not have string type as other matured programming languages which can handle UTF-8 and Unicode. String in this article is basically string in C, a continuous memory of bytes.
Because it is a continuous memory of bytes, it can possibly be immutable or mutable, depending on how it is allocated. In many cases, immutable string is quite similar to slice if not identical. And because it is just a continuous memory of bytes, std.mem provides many functions such as endsWith(), etc.
In C, we know string end with ‘0x0’, but in Zig, it can end with or without ‘0x0’. Zig knows the length anyway. The one ends with ‘0x0’ is called (slice) sentinel.
If you know this string will not change, it would be easily to assigned it as type of []const u8 (without ‘0x0’ in the end). If for some reasons, you need ‘0x0’ in the end, it would be [*:0]const u8. For examples:
const s:[]const u8 = "zig string";
const x:[*:0]const u8 = "zig string";
// s[10] => out of bound
// x[10] => 0x0
Since Zig does the boundary check, I see no reason to use slice sentinel unless handling string from C library. It would be fine to use []const u8 in pure Zig project.
If a string needs to be changed, I would suggest to use ArrayList, which is also a continuous memory of bytes, but has many convenient functions. The bottom line is that ArrayList has items field which behaves similar to []const u8. Therefore, it is quite straightforward to do this:
var content = std.ArrayList(u8).init(allocator); // define your allocator
defer content.deinit();
while (try in_stream.readUntilDelimiterOrEof(&file_buf, '\n')) |line| {
// Read file content from in_stream
// Do some processes
// Append to ArrayList
_ = try content.writer().write(line);
}
// Convert back to []const u8
const result:[]const u8 = allocator.dupe(u8, content.items);
defer allocator.desory(result.ptr);
This approach would simplify the handling of strings by only using []const u8 for immutable string and ArrayList for mutable one.
Again, this may not be the best approach, but works for me.