In this exercise, you will learn
-
how to open a file
-
how to handle errors using the
Result
-type. -
how to use the
Option
-type. -
how to do some elementary file processing (counting, reading line by line).
-
how to navigate the Rust stdlib documentation
-
how to add external dependencies to your project
Both the Option
and Result
are similar in way. Both have two variants, and
depending on what those variants are, the program may continue in a different way.
The Option Type can have the variant Some(<some other type>)
or None
.
It is used, when you have to handle optional values, for example if you want to
be able to leave a field of a struct empty, go assign the option type to it.
If the field has a value, it is Some(<value>)
, if it is empty, it is None
.
The variants of the Result type are Ok(t)
and Err(e)
. It is used to handle errors.
If an operation was successful, Ok(t)
is returned.
In Ok(t)
, t
can be the empty tuple or a return value.
In Err(e)
, e
contains an error message that can be printed.
Both types can be used with the
|
Template
Clone the teaching material repository at github.com/ferrous-systems/teaching-material.
Then, start your VSCode
in the proper root folder to have Rust-Analyzer
working properly.
git clone https://github.com/ferrous-systems/teaching-material
code teaching-material/assignments/files-match-result-assignment/template/
Your code will use the example data found in files-match-result-assignment/template/src/data.
Task 1: Files and Errors
-
Open the file
"src/data/content.txt"
using File::open and bind the result to the variablef
. -
Find out what type the variable
f
is. Either your IDE shows you, or you can assign a random type to the variable, and run the program. -
match
the two possible patterns,Ok(file)
andErr(e)
to an an appropriate expression, for example:println!("File opened")
andprintln!("Error: {}", e)
IDEs often provide a "quick fix" to roll out all match arms quickly |
Task 2: Reading Files… and Errors
-
import
std::io::prelude::*
-
To use the content of the file, bind the result of the
match
statement to a variable.-
In the other branch of the match statement, change
println!("Error: {}", e)
topanic!("Error: {}", e)
-
-
Read the content of the file into a
String
. Use Read::read_to_string. -
Print the entire content of the file using
println!
-
Handle all errors (the compiler will warn you if you miss one)
Task 3: Reading files line by line… and Errors
-
Construct a BufReader around the file
-
Print the content of the file line by line. The
lines()
- method returns an Iterator over the file. -
Print the number of lines the file contains.
-
lines
returns theResult
-Type, use it to get to the actualString
. -
Filter out the empty lines, and only print the the others. The is_empty method can help you here.
Task 4: Read URLs from file… and Errors
-
Add
url = "2"
to your dependencies section inCargo.toml
-
Write a function that parses each line using the Url Type:
fn parse_url(line: String) → Option<Url>
-
If a line can be parsed successfully, return
Some(url)
,None
otherwise -
In the calling context, only print URLs that parse correctly
-
Test the
parse_url
function
-
Help
Typing variables
Variables can be typed by using :
and a type.
let my_value: String = String::from("test");
match
All arms of the match tree have to result in the same type.