test:zig
This commit is contained in:
75
guide/language/optionals.zig
Normal file
75
guide/language/optionals.zig
Normal file
@@ -0,0 +1,75 @@
|
||||
const expect = @import("std").testing.expect;
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
// Optionals use the syntax `?T` and are used to store the data `null`, or a value of type `T`.
|
||||
test "optional" {
|
||||
var found_index: ?usize = null;
|
||||
const data = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 12 };
|
||||
for (data, 0..) |v, i| {
|
||||
if (v == 10) found_index = i;
|
||||
}
|
||||
try expect(found_index == null);
|
||||
}
|
||||
|
||||
// Optionals support the `orelse` expression, which acts when the optional is null. This unwraps the optional to its child type.
|
||||
test "orelse" {
|
||||
const a: ?f32 = null;
|
||||
const fallback_value: f32 = 0;
|
||||
const b = a orelse fallback_value;
|
||||
try expect(b == 0);
|
||||
try expect(@TypeOf(b) == f32);
|
||||
}
|
||||
|
||||
// `.?` is a shorthand for `orelse unreachable`.
|
||||
// This is used for when you know it is impossible for an optional value to be `null`,
|
||||
// and using this to unwrap a `null` value is detectable illegal behaviour.
|
||||
test "orelse unreachable" {
|
||||
const a: ?f32 = 5;
|
||||
const b = a orelse unreachable;
|
||||
const c = a.?;
|
||||
try expect(b == c);
|
||||
try expect(@TypeOf(c) == f32);
|
||||
}
|
||||
|
||||
// Both `if` expressions and `while` loops support taking optional values as conditions,
|
||||
// allowing you to "capture" the inner non-null value.
|
||||
|
||||
// Here we use an if optional payload capture; a and b are equivalent here.
|
||||
// if (b) |value| captures the value of b (in the cases where b is not null), and makes it available as value.
|
||||
// As in the union example, the captured value is immutable,
|
||||
// but we can still use a pointer capture to modify the value stored in b.
|
||||
test "if optional payload capture" {
|
||||
const a: ?i32 = 5;
|
||||
if (a != null) {
|
||||
const value = a.?;
|
||||
_ = value;
|
||||
}
|
||||
|
||||
var b: ?i32 = 5;
|
||||
if (b) |*value| {
|
||||
value.* += 1;
|
||||
}
|
||||
try expect(b.? == 6);
|
||||
}
|
||||
|
||||
// And with while:
|
||||
var numbers_left: u32 = 4;
|
||||
fn eventuallyNullSequence() ?u32 {
|
||||
if (numbers_left == 0) return null;
|
||||
numbers_left -= 1;
|
||||
return numbers_left;
|
||||
}
|
||||
|
||||
test "while null capture" {
|
||||
var sum: u32 = 0;
|
||||
while (eventuallyNullSequence()) |value| {
|
||||
sum += value;
|
||||
}
|
||||
try expect(sum == 6); // 3 + 2 + 1
|
||||
}
|
||||
|
||||
// Optional pointer and optional slice types do not take up any extra memory compared to non-optional ones.
|
||||
// This is because internally they use the 0 value of the pointer for null.
|
||||
|
||||
// This is how null pointers in Zig work - they must be unwrapped to a non-optional before dereferencing,
|
||||
// which stops null pointer dereferences from happening accidentally.
|
||||
Reference in New Issue
Block a user