mirror of
https://codeberg.org/andyscott/ziglings.git
synced 2024-12-22 06:03:09 -05:00
Added ex 21-26 for error handling
This commit is contained in:
parent
08ec029f20
commit
2de8a8c54d
7 changed files with 241 additions and 0 deletions
46
21_errors.zig
Normal file
46
21_errors.zig
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Believe it or not, sometimes things to wrong in programs.
|
||||
//
|
||||
// In Zig, an error is a value. Errors are named so we can identify
|
||||
// things that can go wrong. Errors are created in "error sets", which
|
||||
// are just a collection of named errors.
|
||||
//
|
||||
// We have the start of an error set, but we're missing the condition
|
||||
// "TooSmall". Please add it where needed!
|
||||
const MyNumberError = error{
|
||||
TooBig,
|
||||
???,
|
||||
TooFour,
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
var nums = [_]u8{2,3,4,5,6};
|
||||
|
||||
for (nums) |n| {
|
||||
std.debug.print("{}", .{n});
|
||||
|
||||
const number_error = numberFail(n);
|
||||
|
||||
if (number_error == MyNumberError.TooBig) {
|
||||
std.debug.print(">4. ", .{});
|
||||
}
|
||||
if (???) {
|
||||
std.debug.print("<4. ", .{});
|
||||
}
|
||||
if (number_error == MyNumberError.TooFour) {
|
||||
std.debug.print("=4. ", .{});
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
// Notice how this function can return any member of the MyNumberError
|
||||
// error set.
|
||||
fn numberFail(n: u8) MyNumberError {
|
||||
if(n > 4) return MyNumberError.TooBig;
|
||||
if(n < 4) return MyNumberError.TooSmall; // <---- this one is free!
|
||||
return MyNumberError.TooFour;
|
||||
}
|
30
22_errors2.zig
Normal file
30
22_errors2.zig
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// A common case for errors is a situation where we're expecting to
|
||||
// have a value OR something has gone wrong. Take this example:
|
||||
//
|
||||
// var text: Text = getText('foo.txt');
|
||||
//
|
||||
// What happens if getText() can't find 'foo.txt'? How do we express
|
||||
// this in Zig?
|
||||
//
|
||||
// Zig let's us make what's called an "error union" which is a value
|
||||
// which could either be a regular value OR an error from a set:
|
||||
//
|
||||
// var text: MyErrorSet!Text = getText('foo.txt');
|
||||
//
|
||||
// For now, let's just see if we can try making an error union!
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
const MyNumberError = error{ TooSmall };
|
||||
|
||||
pub fn main() void {
|
||||
var my_number: ??? = 5;
|
||||
|
||||
// Looks like my_number will need to either store a number OR
|
||||
// an error. Can you set the type correctly above?
|
||||
my_number = MyNumberError.TooSmall;
|
||||
|
||||
std.debug.print("I compiled!", .{});
|
||||
}
|
||||
|
28
23_errors3.zig
Normal file
28
23_errors3.zig
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// One way to deal with error unions is to "catch" any error and
|
||||
// replace it with a default value.
|
||||
//
|
||||
// foo = canFail() catch 6;
|
||||
//
|
||||
// If canFail() fails, foo will equal 6.
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
const MyNumberError = error{ TooSmall };
|
||||
|
||||
pub fn main() void {
|
||||
var a: u32 = addTwenty(44) catch 22;
|
||||
var b: u32 = addTwenty(4) ??? 22;
|
||||
|
||||
std.debug.print("a={}, b={}", .{a,b});
|
||||
}
|
||||
|
||||
// Please provide the return type from this function.
|
||||
// Hint: it'll be an error union.
|
||||
fn addTwenty(n: u32) ??? {
|
||||
if (n < 5) {
|
||||
return MyNumberError.TooSmall;
|
||||
} else {
|
||||
return n + 20;
|
||||
}
|
||||
}
|
68
24_errors4.zig
Normal file
68
24_errors4.zig
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// Using `catch` to replace an error with a default value is a bit
|
||||
// of a blunt instrument since it doesn't matter what the error is.
|
||||
//
|
||||
// Catch lets us capture the error value and perform additional
|
||||
// actions with this form:
|
||||
//
|
||||
// canFail() catch |err| {
|
||||
// if (err == FishError.TunaMalfunction) {
|
||||
// ...
|
||||
// }
|
||||
// };
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
const MyNumberError = error{
|
||||
TooSmall,
|
||||
TooBig,
|
||||
};
|
||||
|
||||
pub fn main() void {
|
||||
// The "catch 0" below is just our way of dealing with the fact
|
||||
// that makeJustRight() returns a error union (for now).
|
||||
var a: u32 = makeJustRight(44) catch 0;
|
||||
var b: u32 = makeJustRight(14) catch 0;
|
||||
var c: u32 = makeJustRight(4) catch 0;
|
||||
|
||||
std.debug.print("a={}, b={}, c={}", .{a,b,c});
|
||||
}
|
||||
|
||||
// In this silly example we've split the responsibility of making
|
||||
// a number just right into four (!) functions:
|
||||
//
|
||||
// makeJustRight() Calls fixTooBig(), cannot fix any errors.
|
||||
// fixTooBig() Calls fixTooSmall(), fixes TooBig errors.
|
||||
// fixTooSmall() Calls detectProblems(), fixes TooSmall errors.
|
||||
// detectProblems() Returns the number or an error.
|
||||
//
|
||||
fn makeJustRight(n: u32) MyNumberError!u32 {
|
||||
return fixTooBig(n) catch |err| { return err; };
|
||||
}
|
||||
|
||||
fn fixTooBig(n: u32) MyNumberError!u32 {
|
||||
return fixTooSmall(n) catch |err| {
|
||||
if (err == MyNumberError.TooBig) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
}
|
||||
|
||||
fn fixTooSmall(n: u32) MyNumberError!u32 {
|
||||
// Oh dear, this is missing a lot! But don't worry, it's nearly
|
||||
// identical to fixTooBig() above.
|
||||
//
|
||||
// If we get a TooSmall error, we should return 10.
|
||||
// If we get any other error, we should return that error.
|
||||
// Otherwise, we return the u32 number.
|
||||
return detectProblems(n) ???
|
||||
}
|
||||
|
||||
fn detectProblems(n: u32) MyNumberError!u32 {
|
||||
if (n < 10) return MyNumberError.TooSmall;
|
||||
if (n > 20) return MyNumberError.TooBig;
|
||||
return n;
|
||||
}
|
||||
|
40
25_errors5.zig
Normal file
40
25_errors5.zig
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Zig has a handy "try" shortcut for this common error handling pattern:
|
||||
//
|
||||
// canFail() catch |err| return err;
|
||||
//
|
||||
// which can be more compactly written as:
|
||||
//
|
||||
// try canFail();
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
const MyNumberError = error{
|
||||
TooSmall,
|
||||
TooBig,
|
||||
};
|
||||
|
||||
pub fn main() void {
|
||||
var a: u32 = addFive(44) catch 0;
|
||||
var b: u32 = addFive(14) catch 0;
|
||||
var c: u32 = addFive(4) catch 0;
|
||||
|
||||
std.debug.print("a={}, b={}, c={}", .{a,b,c});
|
||||
}
|
||||
|
||||
fn addFive(n: u32) MyNumberError!u32 {
|
||||
//
|
||||
// This function needs to return any error which might come back from fix().
|
||||
// Please use a "try" statement rather than a "catch".
|
||||
//
|
||||
var x = detect(n);
|
||||
|
||||
return x + 5;
|
||||
}
|
||||
|
||||
fn detect(n: u32) MyNumberError!u32 {
|
||||
if (n < 10) return MyNumberError.TooSmall;
|
||||
if (n > 20) return MyNumberError.TooBig;
|
||||
return n;
|
||||
}
|
||||
|
23
26_hello2.zig
Normal file
23
26_hello2.zig
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Great news! Now we know enough to understand a "real" Hello World
|
||||
// program in Zig - one that uses the system Standard Out resource...which
|
||||
// can fail!
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
// Take note that this main() definition now returns "!void" rather
|
||||
// than just "void". Since there's no specific error type, this means
|
||||
// that Zig will infer the error type. This is appropriate in the case
|
||||
// of main(), but can have consequences elsewhere.
|
||||
pub fn main() !void {
|
||||
|
||||
// We get a Writer for Standard Out so we can print() to it.
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
// Unlike std.debug.print(), the Standard Out writer can fail
|
||||
// with an error. We don't care _what_ the error is, we want
|
||||
// to be able to pass it up as a return value of main().
|
||||
//
|
||||
// We just learned of a single statement which can accomplish this.
|
||||
stdout.print("Hello world!\n", .{});
|
||||
}
|
6
ziglings
6
ziglings
|
@ -88,6 +88,12 @@ check_it 17_quiz2.zig "8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16" "This is a
|
|||
check_it 18_functions.zig "Question: 42" "Can you help write the function?"
|
||||
check_it 19_functions2.zig "2 4 8 16"
|
||||
check_it 20_quiz3.zig "32 64 128 256" "Unexpected pop quiz! Help!"
|
||||
check_it 21_errors.zig "2<4. 3<4. 4=4. 5>4. 6>4." "What's the deal with fours?"
|
||||
check_it 22_errors2.zig "I compiled" "Get the error union type right to allow this to compile."
|
||||
check_it 23_errors3.zig "a=64, b=22"
|
||||
check_it 24_errors4.zig "a=20, b=14, c=10"
|
||||
check_it 25_errors5.zig "a=0, b=19, c=0"
|
||||
check_it 26_hello2.zig "Hello world" "Try using a try!"
|
||||
|
||||
echo
|
||||
echo " __ __ _ "
|
||||
|
|
Loading…
Reference in a new issue