This section collects the exercises for the chapter. They are meant to be small programs. Each one should compile and run.
This section collects the exercises for the chapter. They are meant to be small programs. Each one should compile and run.
Exercise 3-1. Write a block expression that sets x to 10 + 20.
const x = blk: {
break :blk 10 + 20;
};Exercise 3-2. Write a block expression that classifies an integer as "small" or "large".
const label = classify: {
if (n < 100) break :classify "small";
break :classify "large";
};Exercise 3-3. Put a defer inside an inner block and observe when it runs.
const std = @import("std");
pub fn main() void {
std.debug.print("before\n", .{});
{
defer std.debug.print("leaving inner block\n", .{});
std.debug.print("inside\n", .{});
}
std.debug.print("after\n", .{});
}Exercise 3-4. Try to return two different value types from one block expression and read the compiler error.
const x = blk: {
if (true) break :blk 10;
break :blk "ten";
};This should fail. One branch gives an integer. The other gives a string.
Exercise 3-5. Write an if expression that returns the smaller of two integers.
const smaller = if (a < b) a else b;Exercise 3-6. Rewrite an ordinary if statement as an expression.
Before:
var result: i32 = 0;
if (n < 0) {
result = -n;
} else {
result = n;
}After:
const result = if (n < 0) -n else n;Exercise 3-7. Use if with an optional value.
const std = @import("std");
pub fn main() void {
const maybe_name: ?[]const u8 = "zig";
if (maybe_name) |name| {
std.debug.print("{s}\n", .{name});
} else {
std.debug.print("no name\n", .{});
}
}Exercise 3-8. Write a function that returns "even" or "odd" using an if expression.
fn parity(n: i32) []const u8 {
return if (@mod(n, 2) == 0) "even" else "odd";
}Exercise 3-9. Write a switch that converts digits 0 through 9 to their English names.
fn digitName(n: u8) []const u8 {
return switch (n) {
0 => "zero",
1 => "one",
2 => "two",
3 => "three",
4 => "four",
5 => "five",
6 => "six",
7 => "seven",
8 => "eight",
9 => "nine",
else => "not a digit",
};
}Exercise 3-10. Write a switch over an enum named Direction with cases north, south, east, and west.
const Direction = enum {
north,
south,
east,
west,
};
fn directionName(d: Direction) []const u8 {
return switch (d) {
.north => "north",
.south => "south",
.east => "east",
.west => "west",
};
}Exercise 3-11. Add a new enum case and observe which switches must change.
const Direction = enum {
north,
south,
east,
west,
center,
};After adding center, the previous switch no longer covers every case. Add:
.center => "center",Exercise 3-12. Write a tagged union for a simple token: integer, left parenthesis, right parenthesis, plus, and minus. Use switch to print each token.
const std = @import("std");
const Token = union(enum) {
integer: i64,
left_paren,
right_paren,
plus,
minus,
};
fn printToken(tok: Token) void {
switch (tok) {
.integer => |n| std.debug.print("integer {d}\n", .{n}),
.left_paren => std.debug.print("(\n", .{}),
.right_paren => std.debug.print(")\n", .{}),
.plus => std.debug.print("+\n", .{}),
.minus => std.debug.print("-\n", .{}),
}
}Exercise 3-13. Write a while loop that prints the numbers from 1 to 10.
var i: usize = 1;
while (i <= 10) : (i += 1) {
std.debug.print("{d}\n", .{i});
}Exercise 3-14. Write a loop that prints only even numbers below 20.
var i: usize = 0;
while (i < 20) : (i += 1) {
if (i % 2 != 0) continue;
std.debug.print("{d}\n", .{i});
}Exercise 3-15. Write a search loop that finds the first zero in an array.
const data = [_]i32{ 3, 4, 0, 8 };
var i: usize = 0;
const index = while (i < data.len) : (i += 1) {
if (data[i] == 0) break i;
} else data.len;Exercise 3-16. Change the search loop so it returns null when no zero is present.
const data = [_]i32{ 3, 4, 9, 8 };
var i: usize = 0;
const index: ?usize = while (i < data.len) : (i += 1) {
if (data[i] == 0) break i;
} else null;Exercise 3-17. Write a for loop that prints every element in an array.
const data = [_]i32{ 10, 20, 30 };
for (data) |x| {
std.debug.print("{d}\n", .{x});
}Exercise 3-18. Print each element with its index.
const data = [_]i32{ 10, 20, 30 };
for (data, 0..) |x, i| {
std.debug.print("{d}: {d}\n", .{ i, x });
}Exercise 3-19. Use pointer capture to double every number in an array.
var data = [_]i32{ 1, 2, 3, 4 };
for (&data) |*x| {
x.* *= 2;
}Exercise 3-20. Write a for expression that returns the index of the first even number, or null if there is none.
const data = [_]i32{ 1, 3, 7, 10 };
const index: ?usize = for (data, 0..) |x, i| {
if (@mod(x, 2) == 0) break i;
} else null;Exercise 3-21. Write a loop that stops when it finds zero.
const data = [_]i32{ 5, 4, 0, 2 };
for (data) |x| {
if (x == 0) break;
std.debug.print("{d}\n", .{x});
}Exercise 3-22. Write a loop that skips negative numbers and prints the rest.
const data = [_]i32{ 3, -1, 5, -8, 13 };
for (data) |x| {
if (x < 0) continue;
std.debug.print("{d}\n", .{x});
}Exercise 3-23. Write nested loops that search a two-dimensional array.
const table = [_][3]i32{
.{ 1, 2, 3 },
.{ 4, 5, 6 },
.{ 7, 8, 9 },
};
const target = 8;
for (table, 0..) |row, r| {
for (row, 0..) |value, c| {
if (value == target) {
std.debug.print("found at {d}, {d}\n", .{ r, c });
}
}
}Exercise 3-24. Rewrite the nested search using a labeled break.
const table = [_][3]i32{
.{ 1, 2, 3 },
.{ 4, 5, 6 },
.{ 7, 8, 9 },
};
const target = 8;
const found = search: for (table, 0..) |row, r| {
for (row, 0..) |value, c| {
if (value == target) {
break :search .{ r, c };
}
}
} else null;Exercise 3-25. Write a program with two deferred prints and observe the order.
const std = @import("std");
pub fn main() void {
defer std.debug.print("one\n", .{});
defer std.debug.print("two\n", .{});
}The output is:
two
oneExercise 3-26. Put a defer inside an inner block and observe when it runs.
const std = @import("std");
pub fn main() void {
{
defer std.debug.print("inner defer\n", .{});
std.debug.print("inner body\n", .{});
}
std.debug.print("outer body\n", .{});
}Exercise 3-27. Put a defer inside a loop and observe that it runs once per iteration.
const std = @import("std");
pub fn main() void {
for (0..3) |i| {
defer std.debug.print("leave {d}\n", .{i});
std.debug.print("enter {d}\n", .{i});
}
}Exercise 3-28. Open a file and use defer to close it.
const std = @import("std");
pub fn main() !void {
const file = try std.fs.cwd().openFile("input.txt", .{});
defer file.close();
_ = file;
}