diff --git a/learn/basic/process_control/decision.md b/learn/basic/process_control/decision.md index d5463371..c08dc6cd 100644 --- a/learn/basic/process_control/decision.md +++ b/learn/basic/process_control/decision.md @@ -55,4 +55,96 @@ pub fn main() !void { ### 解构可选类型 +事实上,解构可选类型操作很简单: + +```zig +const b: ?u32 = null; +if (b) |real_b| { + unreachable; +} else { + try expect(true); +} +``` + +以上代码的 `else` 分支并非必要,我们结构后获得 `real_b` 就是 `u32` 类型,但是注意我们获得的捕获是只读的! + +如果我们想操纵值的内容,可以选择捕获对应的指针: + +```zig +var c: ?u32 = 3; +if (c) |*value| { + value.* = 2; +} +``` + +`*` 运算符就表示我们选择捕获这个值对应的指针,因此我们可以通过操控指针来修改其值。 + ### 解构错误联合类型 + +解构错误联合类型类似与解构可选类型: + +```zig +const a: anyerror!u32 = 0; +if (a) |value| { + try expect(value == 0); +} else |err| { + _ = err; + unreachable; +} +``` + +以上代码中 `value` 类型为 `u32`,else 分支捕获的是错误,即 `err` 的类型将会是 `anyerror`,这是由我们之前显式声明的,否则将会是由编译器推导的。 + +为了仅检测错误,我们可以这样做: + +```zig +if (b) |_| {} else |err| { + try expect(err == error.BadValue); +} +``` + +同样支持捕获指针来操作值: + +```zig +var c: anyerror!u32 = 3; +if (c) |*value| { + value.* = 9; +} else |_| { + unreachable; +} +``` + +::: warning + +那么 if 是如何解构错误联合可选类型的呢? + +答案是 if 会先尝试解构错误联合类型,再解构可选类型: + +```zig +const a: anyerror!?u32 = 0; +if (a) |optional_value| { + try expect(optional_value.? == 0); +} else |err| { + _ = err; + unreachable; +} +``` + +以上代码中的 `optional_value` 就是可选类型 `?u32`,我们可以在内部继续使用 if 来解构它。 + +在错误联合可选类型上也可以使用指针捕获: + +```zig +var d: anyerror!?u32 = 3; +if (d) |*optional_value| { + if (optional_value.*) |*value| { + value.* = 9; + } +} else |_| { + unreachable; +} +``` + +以上代码中,`*optional_value` 捕获的是可选类型的指针,我们在内部尝试解引用后再一次捕获指针来进行操作。 + +::: \ No newline at end of file diff --git a/learn/basic/process_control/loop.md b/learn/basic/process_control/loop.md index 411ec1b4..3b78c758 100644 --- a/learn/basic/process_control/loop.md +++ b/learn/basic/process_control/loop.md @@ -339,4 +339,82 @@ fn typeNameLength(comptime T: type) usize { ### 解构可选类型 -### 结构错误联合类型 +像 `if` 一样,`while` 也会尝试解构可选类型,并在遇到 `null` 时终止循环。 + +::: code-group + +```zig [default] +while (eventuallyNullSequence()) |value| { + sum2 += value; +} else { + std.debug.print("meet a null\n", .{}); +} +// 还可以使用else分支,碰到第一个 null 时触发并退出循环 +``` + +```zig [more] +const std = @import("std"); + +var numbers_left: u32 = undefined; +fn eventuallyNullSequence() ?u32 { + return if (numbers_left == 0) null else blk: { + numbers_left -= 1; + break :blk numbers_left; + }; +} + +pub fn main() !void { + var sum2: u32 = 0; + numbers_left = 3; + while (eventuallyNullSequence()) |value| { + sum2 += value; + } else { + std.debug.print("meet a null\n", .{}); + } + // 还可以使用else分支,碰到第一个 null 时触发并退出循环 +} +``` + +::: + +当 `|x|` 语法出现在 `while` 表达式上,`while` 条件必须是可选类型。 + +### 解构错误联合类型 + +和上面类似,同样可以解构错误联合类型,`while` 分别会捕获错误和有效负载,当错误发生时,转到 `else` 分支执行,并退出: + +::: code-group + +```zig [default] +while (eventuallyErrorSequence()) |value| { + sum1 += value; +} else |err| { + std.debug.print("meet a err: {}\n", .{err}); +} +``` + +```zig [more] +const std = @import("std"); +var numbers_left: u32 = undefined; + +fn eventuallyErrorSequence() anyerror!u32 { + return if (numbers_left == 0) error.ReachedZero else blk: { + numbers_left -= 1; + break :blk numbers_left; + }; +} + +pub fn main() !void { + var sum1: u32 = 0; + numbers_left = 3; + while (eventuallyErrorSequence()) |value| { + sum1 += value; + } else |err| { + std.debug.print("meet a err: {}\n", .{err}); + } +} +``` + +当 `else |x|` 时语法出现在 `while` 表达式上,`while` 条件必须是错误联合类型。 + +::: \ No newline at end of file