Delete excercies
This commit is contained in:
parent
5b989095cd
commit
f81fe2b60c
|
@ -1,24 +0,0 @@
|
||||||
# Exercise to Book Chapter mapping
|
|
||||||
|
|
||||||
| Exercise | Book Chapter |
|
|
||||||
|------------------------|--------------|
|
|
||||||
| variables | §3.1 |
|
|
||||||
| functions | §3.3 |
|
|
||||||
| if | §3.5 |
|
|
||||||
| move_semantics | §4.1 |
|
|
||||||
| primitive_types | §4.3 |
|
|
||||||
| structs | §5.1 |
|
|
||||||
| enums | §6 |
|
|
||||||
| modules | §7.2 |
|
|
||||||
| collections | §8.1 |
|
|
||||||
| strings | §8.2 |
|
|
||||||
| error_handling | §9 |
|
|
||||||
| generics | §10 |
|
|
||||||
| option | §10.1 |
|
|
||||||
| traits | §10.2 |
|
|
||||||
| tests | §11.1 |
|
|
||||||
| standard_library_types | §13.2 |
|
|
||||||
| threads | §16.1 |
|
|
||||||
| macros | §19.6 |
|
|
||||||
| clippy | n/a |
|
|
||||||
| conversions | n/a |
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Clippy
|
|
||||||
|
|
||||||
The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
|
|
||||||
|
|
||||||
If you used the installation script for Rustlings, Clippy should be already installed.
|
|
||||||
If not you can install it manually via `rustup component add clippy`.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [GitHub Repository](https://github.com/rust-lang/rust-clippy).
|
|
|
@ -1,17 +0,0 @@
|
||||||
// clippy1.rs
|
|
||||||
// The Clippy tool is a collection of lints to analyze your code
|
|
||||||
// so you can catch common mistakes and improve your Rust code.
|
|
||||||
//
|
|
||||||
// For these exercises the code will fail to compile when there are clippy warnings
|
|
||||||
// check clippy's suggestions from the output to solve the exercise.
|
|
||||||
// Execute `rustlings hint clippy1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x = 1.2331f64;
|
|
||||||
let y = 1.2332f64;
|
|
||||||
if y != x {
|
|
||||||
println!("Success!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// clippy2.rs
|
|
||||||
// Make me compile! Execute `rustlings hint clippy2` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut res = 42;
|
|
||||||
let option = Some(12);
|
|
||||||
for x in option {
|
|
||||||
res += x;
|
|
||||||
}
|
|
||||||
println!("{}", res);
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Collections
|
|
||||||
|
|
||||||
Rust’s standard library includes a number of very useful data
|
|
||||||
structures called collections. Most other data types represent one
|
|
||||||
specific value, but collections can contain multiple values. Unlike
|
|
||||||
the built-in array and tuple types, the data these collections point
|
|
||||||
to is stored on the heap, which means the amount of data does not need
|
|
||||||
to be known at compile time and can grow or shrink as the program
|
|
||||||
runs.
|
|
||||||
|
|
||||||
This exercise will get you familiar with two fundamental data
|
|
||||||
structures that are used very often in Rust programs:
|
|
||||||
|
|
||||||
* A *vector* allows you to store a variable number of values next to
|
|
||||||
each other.
|
|
||||||
* A *hash map* allows you to associate a value with a particular key.
|
|
||||||
You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
|
|
||||||
[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html)
|
|
|
@ -1,44 +0,0 @@
|
||||||
// hashmap1.rs
|
|
||||||
// A basket of fruits in the form of a hash map needs to be defined.
|
|
||||||
// The key represents the name of the fruit and the value represents
|
|
||||||
// how many of that particular fruit is in the basket. You have to put
|
|
||||||
// at least three different types of fruits (e.g apple, banana, mango)
|
|
||||||
// in the basket and the total count of all the fruits should be at
|
|
||||||
// least five.
|
|
||||||
//
|
|
||||||
// Make me compile and pass the tests!
|
|
||||||
//
|
|
||||||
// Execute the command `rustlings hint hashmap1` if you need
|
|
||||||
// hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
fn fruit_basket() -> HashMap<String, u32> {
|
|
||||||
let mut basket = // TODO: declare your hash map here.
|
|
||||||
|
|
||||||
// Two bananas are already given for you :)
|
|
||||||
basket.insert(String::from("banana"), 2);
|
|
||||||
|
|
||||||
// TODO: Put more fruits in your basket here.
|
|
||||||
|
|
||||||
basket
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn at_least_three_types_of_fruits() {
|
|
||||||
let basket = fruit_basket();
|
|
||||||
assert!(basket.len() >= 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn at_least_five_fruits() {
|
|
||||||
let basket = fruit_basket();
|
|
||||||
assert!(basket.values().sum::<u32>() >= 5);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
// hashmap2.rs
|
|
||||||
|
|
||||||
// A basket of fruits in the form of a hash map is given. The key
|
|
||||||
// represents the name of the fruit and the value represents how many
|
|
||||||
// of that particular fruit is in the basket. You have to put *MORE
|
|
||||||
// THAN 11* fruits in the basket. Three types of fruits - Apple (4),
|
|
||||||
// Mango (2) and Lychee (5) are already given in the basket. You are
|
|
||||||
// not allowed to insert any more of these fruits!
|
|
||||||
//
|
|
||||||
// Make me pass the tests!
|
|
||||||
//
|
|
||||||
// Execute the command `rustlings hint hashmap2` if you need
|
|
||||||
// hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq)]
|
|
||||||
enum Fruit {
|
|
||||||
Apple,
|
|
||||||
Banana,
|
|
||||||
Mango,
|
|
||||||
Lychee,
|
|
||||||
Pineapple,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
|
|
||||||
let fruit_kinds = vec![
|
|
||||||
Fruit::Apple,
|
|
||||||
Fruit::Banana,
|
|
||||||
Fruit::Mango,
|
|
||||||
Fruit::Lychee,
|
|
||||||
Fruit::Pineapple,
|
|
||||||
];
|
|
||||||
|
|
||||||
for fruit in fruit_kinds {
|
|
||||||
// TODO: Put new fruits if not already present. Note that you
|
|
||||||
// are not allowed to put any type of fruit that's already
|
|
||||||
// present!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn get_fruit_basket() -> HashMap<Fruit, u32> {
|
|
||||||
let mut basket = HashMap::<Fruit, u32>::new();
|
|
||||||
basket.insert(Fruit::Apple, 4);
|
|
||||||
basket.insert(Fruit::Mango, 2);
|
|
||||||
basket.insert(Fruit::Lychee, 5);
|
|
||||||
|
|
||||||
basket
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_given_fruits_are_not_modified() {
|
|
||||||
let mut basket = get_fruit_basket();
|
|
||||||
fruit_basket(&mut basket);
|
|
||||||
assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
|
|
||||||
assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
|
|
||||||
assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn at_least_five_types_of_fruits() {
|
|
||||||
let mut basket = get_fruit_basket();
|
|
||||||
fruit_basket(&mut basket);
|
|
||||||
let count_fruit_kinds = basket.len();
|
|
||||||
assert!(count_fruit_kinds >= 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn greater_than_eleven_fruits() {
|
|
||||||
let mut basket = get_fruit_basket();
|
|
||||||
fruit_basket(&mut basket);
|
|
||||||
let count = basket.values().sum::<u32>();
|
|
||||||
assert!(count > 11);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
// vec1.rs
|
|
||||||
// Your task is to create a `Vec` which holds the exact same elements
|
|
||||||
// as in the array `a`.
|
|
||||||
// Make me compile and pass the test!
|
|
||||||
// Execute the command `rustlings hint vec1` if you need hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn array_and_vec() -> ([i32; 4], Vec<i32>) {
|
|
||||||
let a = [10, 20, 30, 40]; // a plain array
|
|
||||||
let v = // TODO: declare your vector here with the macro for vectors
|
|
||||||
|
|
||||||
(a, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_array_and_vec_similarity() {
|
|
||||||
let (a, v) = array_and_vec();
|
|
||||||
assert_eq!(a, v[..]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
// vec2.rs
|
|
||||||
// A Vec of even numbers is given. Your task is to complete the loop
|
|
||||||
// so that each number in the Vec is multiplied by 2.
|
|
||||||
//
|
|
||||||
// Make me pass the test!
|
|
||||||
//
|
|
||||||
// Execute the command `rustlings hint vec2` if you need
|
|
||||||
// hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
|
|
||||||
for i in v.iter_mut() {
|
|
||||||
// TODO: Fill this up so that each element in the Vec `v` is
|
|
||||||
// multiplied by 2.
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, `v` should be equal to [4, 8, 12, 16, 20].
|
|
||||||
v
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_vec_loop() {
|
|
||||||
let v: Vec<i32> = (1..).filter(|x| x % 2 == 0).take(5).collect();
|
|
||||||
let ans = vec_loop(v.clone());
|
|
||||||
|
|
||||||
assert_eq!(ans, v.iter().map(|x| x * 2).collect::<Vec<i32>>());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
# Type conversions
|
|
||||||
|
|
||||||
Rust offers a multitude of ways to convert a value of a given type into another type.
|
|
||||||
|
|
||||||
The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this.
|
|
||||||
|
|
||||||
Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module.
|
|
||||||
The traits are the following:
|
|
||||||
- `From` and `Into` covered in [`from_into`](from_into.rs)
|
|
||||||
- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs)
|
|
||||||
- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs)
|
|
||||||
|
|
||||||
Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking.
|
|
||||||
|
|
||||||
These should be the main ways ***within the standard library*** to convert data into your desired types.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
These are not directly covered in the book, but the standard library has a great documentation for it.
|
|
||||||
- [conversions](https://doc.rust-lang.org/std/convert/index.html)
|
|
||||||
- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html)
|
|
|
@ -1,52 +0,0 @@
|
||||||
// AsRef and AsMut allow for cheap reference-to-reference conversions.
|
|
||||||
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
|
|
||||||
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
// Obtain the number of bytes (not characters) in the given argument
|
|
||||||
// Add the AsRef trait appropriately as a trait bound
|
|
||||||
fn byte_counter<T>(arg: T) -> usize {
|
|
||||||
arg.as_ref().as_bytes().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the number of characters (not bytes) in the given argument
|
|
||||||
// Add the AsRef trait appropriately as a trait bound
|
|
||||||
fn char_counter<T>(arg: T) -> usize {
|
|
||||||
arg.as_ref().chars().count()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let s = "Café au lait";
|
|
||||||
println!("{}", char_counter(s));
|
|
||||||
println!("{}", byte_counter(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn different_counts() {
|
|
||||||
let s = "Café au lait";
|
|
||||||
assert_ne!(char_counter(s), byte_counter(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn same_counts() {
|
|
||||||
let s = "Cafe au lait";
|
|
||||||
assert_eq!(char_counter(s), byte_counter(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn different_counts_using_string() {
|
|
||||||
let s = String::from("Café au lait");
|
|
||||||
assert_ne!(char_counter(s.clone()), byte_counter(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn same_counts_using_string() {
|
|
||||||
let s = String::from("Cafe au lait");
|
|
||||||
assert_eq!(char_counter(s.clone()), byte_counter(s));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
// The From trait is used for value-to-value conversions.
|
|
||||||
// If From is implemented correctly for a type, the Into trait should work conversely.
|
|
||||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Person {
|
|
||||||
name: String,
|
|
||||||
age: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
// We implement the Default trait to use it as a fallback
|
|
||||||
// when the provided string is not convertible into a Person object
|
|
||||||
impl Default for Person {
|
|
||||||
fn default() -> Person {
|
|
||||||
Person {
|
|
||||||
name: String::from("John"),
|
|
||||||
age: 30,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Your task is to complete this implementation
|
|
||||||
// in order for the line `let p = Person::from("Mark,20")` to compile
|
|
||||||
// Please note that you'll need to parse the age component into a `usize`
|
|
||||||
// with something like `"4".parse::<usize>()`. The outcome of this needs to
|
|
||||||
// be handled appropriately.
|
|
||||||
//
|
|
||||||
// Steps:
|
|
||||||
// 1. If the length of the provided string is 0, then return the default of Person
|
|
||||||
// 2. Split the given string on the commas present in it
|
|
||||||
// 3. Extract the first element from the split operation and use it as the name
|
|
||||||
// 4. If the name is empty, then return the default of Person
|
|
||||||
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
|
|
||||||
// If while parsing the age, something goes wrong, then return the default of Person
|
|
||||||
// Otherwise, then return an instantiated Person object with the results
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
impl From<&str> for Person {
|
|
||||||
fn from(s: &str) -> Person {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Use the `from` function
|
|
||||||
let p1 = Person::from("Mark,20");
|
|
||||||
// Since From is implemented for Person, we should be able to use Into
|
|
||||||
let p2: Person = "Gerald,70".into();
|
|
||||||
println!("{:?}", p1);
|
|
||||||
println!("{:?}", p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_default() {
|
|
||||||
// Test that the default person is 30 year old John
|
|
||||||
let dp = Person::default();
|
|
||||||
assert_eq!(dp.name, "John");
|
|
||||||
assert_eq!(dp.age, 30);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_bad_convert() {
|
|
||||||
// Test that John is returned when bad string is provided
|
|
||||||
let p = Person::from("");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_good_convert() {
|
|
||||||
// Test that "Mark,20" works
|
|
||||||
let p = Person::from("Mark,20");
|
|
||||||
assert_eq!(p.name, "Mark");
|
|
||||||
assert_eq!(p.age, 20);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_bad_age() {
|
|
||||||
// Test that "Mark,twenty" will return the default person due to an error in parsing age
|
|
||||||
let p = Person::from("Mark,twenty");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_missing_comma_and_age() {
|
|
||||||
let p: Person = Person::from("Mark");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_missing_age() {
|
|
||||||
let p: Person = Person::from("Mark,");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_missing_name() {
|
|
||||||
let p: Person = Person::from(",1");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_missing_name_and_age() {
|
|
||||||
let p: Person = Person::from(",");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_missing_name_and_invalid_age() {
|
|
||||||
let p: Person = Person::from(",one");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_trailing_comma() {
|
|
||||||
let p: Person = Person::from("Mike,32,");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_trailing_comma_and_some_string() {
|
|
||||||
let p: Person = Person::from("Mike,32,man");
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 30);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
// This does practically the same thing that TryFrom<&str> does.
|
|
||||||
// Additionally, upon implementing FromStr, you can use the `parse` method
|
|
||||||
// on strings to generate an object of the implementor type.
|
|
||||||
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
|
|
||||||
use std::error;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Person {
|
|
||||||
name: String,
|
|
||||||
age: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
// Steps:
|
|
||||||
// 1. If the length of the provided string is 0, an error should be returned
|
|
||||||
// 2. Split the given string on the commas present in it
|
|
||||||
// 3. Only 2 elements should be returned from the split, otherwise return an error
|
|
||||||
// 4. Extract the first element from the split operation and use it as the name
|
|
||||||
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
|
|
||||||
// with something like `"4".parse::<usize>()`
|
|
||||||
// 5. If while extracting the name and the age something goes wrong, an error should be returned
|
|
||||||
// If everything goes well, then return a Result of a Person object
|
|
||||||
|
|
||||||
impl FromStr for Person {
|
|
||||||
type Err = Box<dyn error::Error>;
|
|
||||||
fn from_str(s: &str) -> Result<Person, Self::Err> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let p = "Mark,20".parse::<Person>().unwrap();
|
|
||||||
println!("{:?}", p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty_input() {
|
|
||||||
assert!("".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn good_input() {
|
|
||||||
let p = "John,32".parse::<Person>();
|
|
||||||
assert!(p.is_ok());
|
|
||||||
let p = p.unwrap();
|
|
||||||
assert_eq!(p.name, "John");
|
|
||||||
assert_eq!(p.age, 32);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn missing_age() {
|
|
||||||
assert!("John,".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn invalid_age() {
|
|
||||||
assert!("John,twenty".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn missing_comma_and_age() {
|
|
||||||
assert!("John".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn missing_name() {
|
|
||||||
assert!(",1".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn missing_name_and_age() {
|
|
||||||
assert!(",".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn missing_name_and_invalid_age() {
|
|
||||||
assert!(",one".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn trailing_comma() {
|
|
||||||
assert!("John,32,".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn trailing_comma_and_some_string() {
|
|
||||||
assert!("John,32,man".parse::<Person>().is_err());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,158 +0,0 @@
|
||||||
// TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
|
|
||||||
// Basically, this is the same as From. The main difference is that this should return a Result type
|
|
||||||
// instead of the target type itself.
|
|
||||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
|
||||||
use std::error;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
struct Color {
|
|
||||||
red: u8,
|
|
||||||
green: u8,
|
|
||||||
blue: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
// Your task is to complete this implementation
|
|
||||||
// and return an Ok result of inner type Color.
|
|
||||||
// You need to create an implementation for a tuple of three integers,
|
|
||||||
// an array of three integers and a slice of integers.
|
|
||||||
//
|
|
||||||
// Note that the implementation for tuple and array will be checked at compile time,
|
|
||||||
// but the slice implementation needs to check the slice length!
|
|
||||||
// Also note that correct RGB color values must be integers in the 0..=255 range.
|
|
||||||
|
|
||||||
// Tuple implementation
|
|
||||||
impl TryFrom<(i16, i16, i16)> for Color {
|
|
||||||
type Error = Box<dyn error::Error>;
|
|
||||||
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array implementation
|
|
||||||
impl TryFrom<[i16; 3]> for Color {
|
|
||||||
type Error = Box<dyn error::Error>;
|
|
||||||
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice implementation
|
|
||||||
impl TryFrom<&[i16]> for Color {
|
|
||||||
type Error = Box<dyn error::Error>;
|
|
||||||
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Use the `from` function
|
|
||||||
let c1 = Color::try_from((183, 65, 14));
|
|
||||||
println!("{:?}", c1);
|
|
||||||
|
|
||||||
// Since From is implemented for Color, we should be able to use Into
|
|
||||||
let c2: Result<Color, _> = [183, 65, 14].try_into();
|
|
||||||
println!("{:?}", c2);
|
|
||||||
|
|
||||||
let v = vec![183, 65, 14];
|
|
||||||
// With slice we should use `from` function
|
|
||||||
let c3 = Color::try_from(&v[..]);
|
|
||||||
println!("{:?}", c3);
|
|
||||||
// or take slice within round brackets and use Into
|
|
||||||
let c4: Result<Color, _> = (&v[..]).try_into();
|
|
||||||
println!("{:?}", c4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_tuple_out_of_range_positive() {
|
|
||||||
assert!(Color::try_from((256, 1000, 10000)).is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_tuple_out_of_range_negative() {
|
|
||||||
assert!(Color::try_from((-1, -10, -256)).is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_tuple_sum() {
|
|
||||||
assert!(Color::try_from((-1, 255, 255)).is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_tuple_correct() {
|
|
||||||
let c: Result<Color, _> = (183, 65, 14).try_into();
|
|
||||||
assert!(c.is_ok());
|
|
||||||
assert_eq!(
|
|
||||||
c.unwrap(),
|
|
||||||
Color {
|
|
||||||
red: 183,
|
|
||||||
green: 65,
|
|
||||||
blue: 14
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_array_out_of_range_positive() {
|
|
||||||
let c: Result<Color, _> = [1000, 10000, 256].try_into();
|
|
||||||
assert!(c.is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_array_out_of_range_negative() {
|
|
||||||
let c: Result<Color, _> = [-10, -256, -1].try_into();
|
|
||||||
assert!(c.is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_array_sum() {
|
|
||||||
let c: Result<Color, _> = [-1, 255, 255].try_into();
|
|
||||||
assert!(c.is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_array_correct() {
|
|
||||||
let c: Result<Color, _> = [183, 65, 14].try_into();
|
|
||||||
assert!(c.is_ok());
|
|
||||||
assert_eq!(
|
|
||||||
c.unwrap(),
|
|
||||||
Color {
|
|
||||||
red: 183,
|
|
||||||
green: 65,
|
|
||||||
blue: 14
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_slice_out_of_range_positive() {
|
|
||||||
let arr = [10000, 256, 1000];
|
|
||||||
assert!(Color::try_from(&arr[..]).is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_slice_out_of_range_negative() {
|
|
||||||
let arr = [-256, -1, -10];
|
|
||||||
assert!(Color::try_from(&arr[..]).is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_slice_sum() {
|
|
||||||
let arr = [-1, 255, 255];
|
|
||||||
assert!(Color::try_from(&arr[..]).is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_slice_correct() {
|
|
||||||
let v = vec![183, 65, 14];
|
|
||||||
let c: Result<Color, _> = Color::try_from(&v[..]);
|
|
||||||
assert!(c.is_ok());
|
|
||||||
assert_eq!(
|
|
||||||
c.unwrap(),
|
|
||||||
Color {
|
|
||||||
red: 183,
|
|
||||||
green: 65,
|
|
||||||
blue: 14
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_slice_excess_length() {
|
|
||||||
let v = vec![0, 0, 0, 0];
|
|
||||||
assert!(Color::try_from(&v[..]).is_err());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_slice_insufficient_length() {
|
|
||||||
let v = vec![0, 0];
|
|
||||||
assert!(Color::try_from(&v[..]).is_err());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Type casting in Rust is done via the usage of the `as` operator.
|
|
||||||
// Please note that the `as` operator is not only used when type casting.
|
|
||||||
// It also helps with renaming imports.
|
|
||||||
//
|
|
||||||
// The goal is to make sure that the division does not fail to compile
|
|
||||||
// and returns the proper type.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn average(values: &[f64]) -> f64 {
|
|
||||||
let total = values.iter().fold(0.0, |a, b| a + b);
|
|
||||||
total / values.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let values = [3.5, 0.3, 13.0, 11.7];
|
|
||||||
println!("{}", average(&values));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn returns_proper_type_and_value() {
|
|
||||||
assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Enums
|
|
||||||
|
|
||||||
Rust allows you to define types called "enums" which enumerate possible values.
|
|
||||||
Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
|
|
||||||
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
|
|
||||||
- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)
|
|
|
@ -1,16 +0,0 @@
|
||||||
// enums1.rs
|
|
||||||
// Make me compile! Execute `rustlings hint enums1` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Message {
|
|
||||||
// TODO: define a few types of messages as used below
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("{:?}", Message::Quit);
|
|
||||||
println!("{:?}", Message::Echo);
|
|
||||||
println!("{:?}", Message::Move);
|
|
||||||
println!("{:?}", Message::ChangeColor);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// enums2.rs
|
|
||||||
// Make me compile! Execute `rustlings hint enums2` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Message {
|
|
||||||
// TODO: define the different variants used below
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Message {
|
|
||||||
fn call(&self) {
|
|
||||||
println!("{:?}", &self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let messages = [
|
|
||||||
Message::Move { x: 10, y: 30 },
|
|
||||||
Message::Echo(String::from("hello world")),
|
|
||||||
Message::ChangeColor(200, 255, 255),
|
|
||||||
Message::Quit,
|
|
||||||
];
|
|
||||||
|
|
||||||
for message in &messages {
|
|
||||||
message.call();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
// enums3.rs
|
|
||||||
// Address all the TODOs to make the tests pass!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
enum Message {
|
|
||||||
// TODO: implement the message variant types based on their usage below
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
x: u8,
|
|
||||||
y: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct State {
|
|
||||||
color: (u8, u8, u8),
|
|
||||||
position: Point,
|
|
||||||
quit: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn change_color(&mut self, color: (u8, u8, u8)) {
|
|
||||||
self.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quit(&mut self) {
|
|
||||||
self.quit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn echo(&self, s: String) {
|
|
||||||
println!("{}", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_position(&mut self, p: Point) {
|
|
||||||
self.position = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process(&mut self, message: Message) {
|
|
||||||
// TODO: create a match expression to process the different message variants
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_match_message_call() {
|
|
||||||
let mut state = State {
|
|
||||||
quit: false,
|
|
||||||
position: Point { x: 0, y: 0 },
|
|
||||||
color: (0, 0, 0),
|
|
||||||
};
|
|
||||||
state.process(Message::ChangeColor((255, 0, 255)));
|
|
||||||
state.process(Message::Echo(String::from("hello world")));
|
|
||||||
state.process(Message::Move(Point { x: 10, y: 15 }));
|
|
||||||
state.process(Message::Quit);
|
|
||||||
|
|
||||||
assert_eq!(state.color, (255, 0, 255));
|
|
||||||
assert_eq!(state.position.x, 10);
|
|
||||||
assert_eq!(state.position.y, 15);
|
|
||||||
assert_eq!(state.quit, true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
# Error handling
|
|
||||||
Most errors aren’t serious enough to require the program to stop entirely.
|
|
||||||
Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to.
|
|
||||||
For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
|
|
||||||
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
|
|
||||||
- [Result](https://doc.rust-lang.org/rust-by-example/error/result.html)
|
|
||||||
- [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html)
|
|
|
@ -1,42 +0,0 @@
|
||||||
// errors1.rs
|
|
||||||
// This function refuses to generate text to be printed on a nametag if
|
|
||||||
// you pass it an empty string. It'd be nicer if it explained what the problem
|
|
||||||
// was, instead of just sometimes returning `None`. The 2nd test currently
|
|
||||||
// does not compile or pass, but it illustrates the behavior we would like
|
|
||||||
// this function to have.
|
|
||||||
// Execute `rustlings hint errors1` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub fn generate_nametag_text(name: String) -> Option<String> {
|
|
||||||
if name.len() > 0 {
|
|
||||||
Some(format!("Hi! My name is {}", name))
|
|
||||||
} else {
|
|
||||||
// Empty names aren't allowed.
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
// This test passes initially if you comment out the 2nd test.
|
|
||||||
// You'll need to update what this test expects when you change
|
|
||||||
// the function under test!
|
|
||||||
#[test]
|
|
||||||
fn generates_nametag_text_for_a_nonempty_name() {
|
|
||||||
assert_eq!(
|
|
||||||
generate_nametag_text("Beyoncé".into()),
|
|
||||||
Some("Hi! My name is Beyoncé".into())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn explains_why_generating_nametag_text_fails() {
|
|
||||||
assert_eq!(
|
|
||||||
generate_nametag_text("".into()),
|
|
||||||
Err("`name` was empty; it must be nonempty.".into())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
// errors2.rs
|
|
||||||
// Say we're writing a game where you can buy items with tokens. All items cost
|
|
||||||
// 5 tokens, and whenever you purchase items there is a processing fee of 1
|
|
||||||
// token. A player of the game will type in how many items they want to buy,
|
|
||||||
// and the `total_cost` function will calculate the total number of tokens.
|
|
||||||
// Since the player typed in the quantity, though, we get it as a string-- and
|
|
||||||
// they might have typed anything, not just numbers!
|
|
||||||
|
|
||||||
// Right now, this function isn't handling the error case at all (and isn't
|
|
||||||
// handling the success case properly either). What we want to do is:
|
|
||||||
// if we call the `parse` function on a string that is not a number, that
|
|
||||||
// function will return a `ParseIntError`, and in that case, we want to
|
|
||||||
// immediately return that error from our function and not try to multiply
|
|
||||||
// and add.
|
|
||||||
|
|
||||||
// There are at least two ways to implement this that are both correct-- but
|
|
||||||
// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
|
|
||||||
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
|
|
||||||
let processing_fee = 1;
|
|
||||||
let cost_per_item = 5;
|
|
||||||
let qty = item_quantity.parse::<i32>();
|
|
||||||
|
|
||||||
Ok(qty * cost_per_item + processing_fee)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn item_quantity_is_a_valid_number() {
|
|
||||||
assert_eq!(total_cost("34"), Ok(171));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn item_quantity_is_an_invalid_number() {
|
|
||||||
assert_eq!(
|
|
||||||
total_cost("beep boop").unwrap_err().to_string(),
|
|
||||||
"invalid digit found in string"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// errors3.rs
|
|
||||||
// This is a program that is trying to use a completed version of the
|
|
||||||
// `total_cost` function from the previous exercise. It's not working though!
|
|
||||||
// Why not? What should we do to fix it?
|
|
||||||
// Execute `rustlings hint errors3` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut tokens = 100;
|
|
||||||
let pretend_user_input = "8";
|
|
||||||
|
|
||||||
let cost = total_cost(pretend_user_input)?;
|
|
||||||
|
|
||||||
if cost > tokens {
|
|
||||||
println!("You can't afford that many!");
|
|
||||||
} else {
|
|
||||||
tokens -= cost;
|
|
||||||
println!("You now have {} tokens.", tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
|
|
||||||
let processing_fee = 1;
|
|
||||||
let cost_per_item = 5;
|
|
||||||
let qty = item_quantity.parse::<i32>()?;
|
|
||||||
|
|
||||||
Ok(qty * cost_per_item + processing_fee)
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
// errors4.rs
|
|
||||||
// Make this test pass! Execute `rustlings hint errors4` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
struct PositiveNonzeroInteger(u64);
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
enum CreationError {
|
|
||||||
Negative,
|
|
||||||
Zero,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PositiveNonzeroInteger {
|
|
||||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
|
||||||
Ok(PositiveNonzeroInteger(value as u64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_creation() {
|
|
||||||
assert!(PositiveNonzeroInteger::new(10).is_ok());
|
|
||||||
assert_eq!(
|
|
||||||
Err(CreationError::Negative),
|
|
||||||
PositiveNonzeroInteger::new(-10)
|
|
||||||
);
|
|
||||||
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
// errors5.rs
|
|
||||||
|
|
||||||
// This program uses a completed version of the code from errors4.
|
|
||||||
// It won't compile right now! Why?
|
|
||||||
// Execute `rustlings hint errors5` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
|
|
||||||
// TODO: update the return type of `main()` to make this compile.
|
|
||||||
fn main() -> Result<(), ParseIntError> {
|
|
||||||
let pretend_user_input = "42";
|
|
||||||
let x: i64 = pretend_user_input.parse()?;
|
|
||||||
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't change anything below this line.
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
struct PositiveNonzeroInteger(u64);
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
enum CreationError {
|
|
||||||
Negative,
|
|
||||||
Zero,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PositiveNonzeroInteger {
|
|
||||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
|
||||||
match value {
|
|
||||||
x if x < 0 => Err(CreationError::Negative),
|
|
||||||
x if x == 0 => Err(CreationError::Zero),
|
|
||||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is required so that `CreationError` can implement `error::Error`.
|
|
||||||
impl fmt::Display for CreationError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let description = match *self {
|
|
||||||
CreationError::Negative => "number is negative",
|
|
||||||
CreationError::Zero => "number is zero",
|
|
||||||
};
|
|
||||||
f.write_str(description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for CreationError {}
|
|
|
@ -1,95 +0,0 @@
|
||||||
// errors6.rs
|
|
||||||
|
|
||||||
// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
|
|
||||||
// for library code, where callers might want to make decisions based on the
|
|
||||||
// error content, instead of printing it out or propagating it further. Here,
|
|
||||||
// we define a custom error type to make it possible for callers to decide
|
|
||||||
// what to do next when our function returns an error.
|
|
||||||
|
|
||||||
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
|
|
||||||
// This is a custom error type that we will be using in `parse_pos_nonzero()`.
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
enum ParsePosNonzeroError {
|
|
||||||
Creation(CreationError),
|
|
||||||
ParseInt(ParseIntError)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParsePosNonzeroError {
|
|
||||||
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
|
|
||||||
ParsePosNonzeroError::Creation(err)
|
|
||||||
}
|
|
||||||
// TODO: add another error conversion function here.
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_pos_nonzero(s: &str)
|
|
||||||
-> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
|
|
||||||
{
|
|
||||||
// TODO: change this to return an appropriate error instead of panicking
|
|
||||||
// when `parse()` returns an error.
|
|
||||||
let x: i64 = s.parse().unwrap();
|
|
||||||
PositiveNonzeroInteger::new(x)
|
|
||||||
.map_err(ParsePosNonzeroError::from_creation)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't change anything below this line.
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
struct PositiveNonzeroInteger(u64);
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
enum CreationError {
|
|
||||||
Negative,
|
|
||||||
Zero,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PositiveNonzeroInteger {
|
|
||||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
|
||||||
match value {
|
|
||||||
x if x < 0 => Err(CreationError::Negative),
|
|
||||||
x if x == 0 => Err(CreationError::Zero),
|
|
||||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_error() {
|
|
||||||
// We can't construct a ParseIntError, so we have to pattern match.
|
|
||||||
assert!(matches!(
|
|
||||||
parse_pos_nonzero("not a number"),
|
|
||||||
Err(ParsePosNonzeroError::ParseInt(_))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_negative() {
|
|
||||||
assert_eq!(
|
|
||||||
parse_pos_nonzero("-555"),
|
|
||||||
Err(ParsePosNonzeroError::Creation(CreationError::Negative))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_zero() {
|
|
||||||
assert_eq!(
|
|
||||||
parse_pos_nonzero("0"),
|
|
||||||
Err(ParsePosNonzeroError::Creation(CreationError::Zero))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_positive() {
|
|
||||||
let x = PositiveNonzeroInteger::new(42);
|
|
||||||
assert!(x.is_ok());
|
|
||||||
assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
# Functions
|
|
||||||
|
|
||||||
Here, you'll learn how to write functions and how Rust's compiler can trace things way back.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
|
|
|
@ -1,8 +0,0 @@
|
||||||
// functions1.rs
|
|
||||||
// Make me compile! Execute `rustlings hint functions1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
call_me();
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// functions2.rs
|
|
||||||
// Make me compile! Execute `rustlings hint functions2` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
call_me(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_me(num:) {
|
|
||||||
for i in 0..num {
|
|
||||||
println!("Ring! Call number {}", i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// functions3.rs
|
|
||||||
// Make me compile! Execute `rustlings hint functions3` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
call_me();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_me(num: u32) {
|
|
||||||
for i in 0..num {
|
|
||||||
println!("Ring! Call number {}", i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// functions4.rs
|
|
||||||
// Make me compile! Execute `rustlings hint functions4` for hints :)
|
|
||||||
|
|
||||||
// This store is having a sale where if the price is an even number, you get
|
|
||||||
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let original_price = 51;
|
|
||||||
println!("Your sale price is {}", sale_price(original_price));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sale_price(price: i32) -> {
|
|
||||||
if is_even(price) {
|
|
||||||
price - 10
|
|
||||||
} else {
|
|
||||||
price - 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_even(num: i32) -> bool {
|
|
||||||
num % 2 == 0
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// functions5.rs
|
|
||||||
// Make me compile! Execute `rustlings hint functions5` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let answer = square(3);
|
|
||||||
println!("The answer is {}", answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn square(num: i32) -> i32 {
|
|
||||||
num * num;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
# Generics
|
|
||||||
|
|
||||||
Generics is the topic of generalizing types and functionalities to broader cases.
|
|
||||||
This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax.
|
|
||||||
Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid.
|
|
||||||
The simplest and most common use of generics is for type parameters.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html)
|
|
||||||
- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html)
|
|
|
@ -1,11 +0,0 @@
|
||||||
// This shopping list program isn't compiling!
|
|
||||||
// Use your knowledge of generics to fix it.
|
|
||||||
|
|
||||||
// Execute `rustlings hint generics1` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut shopping_list: Vec<?> = Vec::new();
|
|
||||||
shopping_list.push("milk");
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// This powerful wrapper provides the ability to store a positive integer value.
|
|
||||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
|
||||||
|
|
||||||
// Execute `rustlings hint generics2` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
struct Wrapper {
|
|
||||||
value: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Wrapper {
|
|
||||||
pub fn new(value: u32) -> Self {
|
|
||||||
Wrapper { value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn store_u32_in_wrapper() {
|
|
||||||
assert_eq!(Wrapper::new(42).value, 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn store_str_in_wrapper() {
|
|
||||||
assert_eq!(Wrapper::new("Foo").value, "Foo");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
// An imaginary magical school has a new report card generation system written in Rust!
|
|
||||||
// Currently the system only supports creating report cards where the student's grade
|
|
||||||
// is represented numerically (e.g. 1.0 -> 5.5).
|
|
||||||
// However, the school also issues alphabetical grades (A+ -> F-) and needs
|
|
||||||
// to be able to print both types of report card!
|
|
||||||
|
|
||||||
// Make the necessary code changes in the struct ReportCard and the impl block
|
|
||||||
// to support alphabetical report cards. Change the Grade in the second test to "A+"
|
|
||||||
// to show that your changes allow alphabetical grades.
|
|
||||||
|
|
||||||
// Execute 'rustlings hint generics3' for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub struct ReportCard {
|
|
||||||
pub grade: f32,
|
|
||||||
pub student_name: String,
|
|
||||||
pub student_age: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReportCard {
|
|
||||||
pub fn print(&self) -> String {
|
|
||||||
format!("{} ({}) - achieved a grade of {}",
|
|
||||||
&self.student_name, &self.student_age, &self.grade)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generate_numeric_report_card() {
|
|
||||||
let report_card = ReportCard {
|
|
||||||
grade: 2.1,
|
|
||||||
student_name: "Tom Wriggle".to_string(),
|
|
||||||
student_age: 12,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
report_card.print(),
|
|
||||||
"Tom Wriggle (12) - achieved a grade of 2.1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generate_alphabetic_report_card() {
|
|
||||||
// TODO: Make sure to change the grade here after you finish the exercise.
|
|
||||||
let report_card = ReportCard {
|
|
||||||
grade: 2.1,
|
|
||||||
student_name: "Gary Plotter".to_string(),
|
|
||||||
student_age: 11,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
report_card.print(),
|
|
||||||
"Gary Plotter (11) - achieved a grade of A+"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
# If
|
|
||||||
|
|
||||||
`if`, the most basic type of control flow, is what you'll learn here.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions)
|
|
|
@ -1,27 +0,0 @@
|
||||||
// if1.rs
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub fn bigger(a: i32, b: i32) -> i32 {
|
|
||||||
// Complete this function to return the bigger number!
|
|
||||||
// Do not use:
|
|
||||||
// - another function call
|
|
||||||
// - additional variables
|
|
||||||
// Execute `rustlings hint if1` for hints
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't mind this for now :)
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ten_is_bigger_than_eight() {
|
|
||||||
assert_eq!(10, bigger(10, 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn fortytwo_is_bigger_than_thirtytwo() {
|
|
||||||
assert_eq!(42, bigger(32, 42));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
// if2.rs
|
|
||||||
|
|
||||||
// Step 1: Make me compile!
|
|
||||||
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
|
|
||||||
// Execute the command `rustlings hint if2` if you want a hint :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub fn fizz_if_foo(fizzish: &str) -> &str {
|
|
||||||
if fizzish == "fizz" {
|
|
||||||
"foo"
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No test changes needed!
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn foo_for_fizz() {
|
|
||||||
assert_eq!(fizz_if_foo("fizz"), "foo")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn bar_for_fuzz() {
|
|
||||||
assert_eq!(fizz_if_foo("fuzz"), "bar")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn default_to_baz() {
|
|
||||||
assert_eq!(fizz_if_foo("literally anything"), "baz")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Macros
|
|
||||||
|
|
||||||
Rust's macro system is very powerful, but also kind of difficult to wrap your
|
|
||||||
head around. We're not going to teach you how to write your own fully-featured
|
|
||||||
macros. Instead, we'll show you how to use and create them.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
|
|
||||||
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)
|
|
|
@ -1,14 +0,0 @@
|
||||||
// macros1.rs
|
|
||||||
// Make me compile! Execute `rustlings hint macros1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
macro_rules! my_macro {
|
|
||||||
() => {
|
|
||||||
println!("Check out my macro!");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
my_macro();
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// macros2.rs
|
|
||||||
// Make me compile! Execute `rustlings hint macros2` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
my_macro!();
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! my_macro {
|
|
||||||
() => {
|
|
||||||
println!("Check out my macro!");
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// macros3.rs
|
|
||||||
// Make me compile, without taking the macro out of the module!
|
|
||||||
// Execute `rustlings hint macros3` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
mod macros {
|
|
||||||
macro_rules! my_macro {
|
|
||||||
() => {
|
|
||||||
println!("Check out my macro!");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
my_macro!();
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// macros4.rs
|
|
||||||
// Make me compile! Execute `rustlings hint macros4` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
macro_rules! my_macro {
|
|
||||||
() => {
|
|
||||||
println!("Check out my macro!");
|
|
||||||
}
|
|
||||||
($val:expr) => {
|
|
||||||
println!("Look at this other macro: {}", $val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
my_macro!();
|
|
||||||
my_macro!(7777);
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
# Modules
|
|
||||||
|
|
||||||
In this section we'll give you an introduction to Rust's module system.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [The Module System](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html)
|
|
|
@ -1,14 +0,0 @@
|
||||||
// modules1.rs
|
|
||||||
// Make me compile! Execute `rustlings hint modules1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
mod sausage_factory {
|
|
||||||
fn make_sausage() {
|
|
||||||
println!("sausage!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
sausage_factory::make_sausage();
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
// modules2.rs
|
|
||||||
// Make me compile! Execute `rustlings hint modules2` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
mod delicious_snacks {
|
|
||||||
use self::fruits::PEAR as fruit;
|
|
||||||
use self::veggies::CUCUMBER as veggie;
|
|
||||||
|
|
||||||
mod fruits {
|
|
||||||
pub const PEAR: &'static str = "Pear";
|
|
||||||
pub const APPLE: &'static str = "Apple";
|
|
||||||
}
|
|
||||||
|
|
||||||
mod veggies {
|
|
||||||
pub const CUCUMBER: &'static str = "Cucumber";
|
|
||||||
pub const CARROT: &'static str = "Carrot";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!(
|
|
||||||
"favorite snacks: {} and {}",
|
|
||||||
delicious_snacks::fruit,
|
|
||||||
delicious_snacks::veggie
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Move Semantics
|
|
||||||
|
|
||||||
These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!!
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
For this section, the book links are especially important.
|
|
||||||
|
|
||||||
- [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
|
|
||||||
- [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)
|
|
|
@ -1,26 +0,0 @@
|
||||||
// move_semantics1.rs
|
|
||||||
// Make me compile! Execute `rustlings hint move_semantics1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let vec0 = Vec::new();
|
|
||||||
|
|
||||||
let vec1 = fill_vec(vec0);
|
|
||||||
|
|
||||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
|
||||||
|
|
||||||
vec1.push(88);
|
|
||||||
|
|
||||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
|
|
||||||
let mut vec = vec;
|
|
||||||
|
|
||||||
vec.push(22);
|
|
||||||
vec.push(44);
|
|
||||||
vec.push(66);
|
|
||||||
|
|
||||||
vec
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// move_semantics2.rs
|
|
||||||
// Make me compile without changing line 13!
|
|
||||||
// Execute `rustlings hint move_semantics2` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let vec0 = Vec::new();
|
|
||||||
|
|
||||||
let mut vec1 = fill_vec(vec0);
|
|
||||||
|
|
||||||
// Do not change the following line!
|
|
||||||
println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);
|
|
||||||
|
|
||||||
vec1.push(88);
|
|
||||||
|
|
||||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
|
|
||||||
let mut vec = vec;
|
|
||||||
|
|
||||||
vec.push(22);
|
|
||||||
vec.push(44);
|
|
||||||
vec.push(66);
|
|
||||||
|
|
||||||
vec
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// move_semantics3.rs
|
|
||||||
// Make me compile without adding new lines-- just changing existing lines!
|
|
||||||
// (no lines with multiple semicolons necessary!)
|
|
||||||
// Execute `rustlings hint move_semantics3` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let vec0 = Vec::new();
|
|
||||||
|
|
||||||
let mut vec1 = fill_vec(vec0);
|
|
||||||
|
|
||||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
|
||||||
|
|
||||||
vec1.push(88);
|
|
||||||
|
|
||||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
|
|
||||||
vec.push(22);
|
|
||||||
vec.push(44);
|
|
||||||
vec.push(66);
|
|
||||||
|
|
||||||
vec
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
// move_semantics4.rs
|
|
||||||
// Refactor this code so that instead of having `vec0` and creating the vector
|
|
||||||
// in `fn main`, we create it within `fn fill_vec` and transfer the
|
|
||||||
// freshly created vector from fill_vec to its caller.
|
|
||||||
// Execute `rustlings hint move_semantics4` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let vec0 = Vec::new();
|
|
||||||
|
|
||||||
let mut vec1 = fill_vec(vec0);
|
|
||||||
|
|
||||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
|
||||||
|
|
||||||
vec1.push(88);
|
|
||||||
|
|
||||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// `fill_vec()` no longer takes `vec: Vec<i32>` as argument
|
|
||||||
fn fill_vec() -> Vec<i32> {
|
|
||||||
let mut vec = vec;
|
|
||||||
|
|
||||||
vec.push(22);
|
|
||||||
vec.push(44);
|
|
||||||
vec.push(66);
|
|
||||||
|
|
||||||
vec
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// move_semantics5.rs
|
|
||||||
// Make me compile without adding, removing, or changing any of the
|
|
||||||
// lines in `main()`.
|
|
||||||
// Execute `rustlings hint move_semantics5` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut x = 100;
|
|
||||||
let y = &mut x;
|
|
||||||
let z = &mut *y;
|
|
||||||
*y += 100;
|
|
||||||
*z += 1000;
|
|
||||||
assert_eq!(x, 1200);
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Option
|
|
||||||
|
|
||||||
Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
|
|
||||||
Option types are very common in Rust code, as they have a number of uses:
|
|
||||||
- Initial values
|
|
||||||
- Return values for functions that are not defined over their entire input range (partial functions)
|
|
||||||
- Return value for otherwise reporting simple errors, where None is returned on error
|
|
||||||
- Optional struct fields
|
|
||||||
- Struct fields that can be loaned or "taken"
|
|
||||||
- Optional function arguments
|
|
||||||
- Nullable pointers
|
|
||||||
- Swapping things out of difficult situations
|
|
||||||
|
|
||||||
## Further Information
|
|
||||||
|
|
||||||
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions)
|
|
||||||
- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
|
|
||||||
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
|
|
|
@ -1,23 +0,0 @@
|
||||||
// option1.rs
|
|
||||||
// Make me compile! Execute `rustlings hint option1` for hints
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
// you can modify anything EXCEPT for this function's sig
|
|
||||||
fn print_number(maybe_number: Option<u16>) {
|
|
||||||
println!("printing: {}", maybe_number.unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
print_number(13);
|
|
||||||
print_number(99);
|
|
||||||
|
|
||||||
let mut numbers: [Option<u16>; 5];
|
|
||||||
for iter in 0..5 {
|
|
||||||
let number_to_add: u16 = {
|
|
||||||
((iter * 1235) + 2) / (4 * 16)
|
|
||||||
};
|
|
||||||
|
|
||||||
numbers[iter as usize] = number_to_add;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
// option2.rs
|
|
||||||
// Make me compile! Execute `rustlings hint option2` for hints
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let optional_word = Some(String::from("rustlings"));
|
|
||||||
// TODO: Make this an if let statement whose value is "Some" type
|
|
||||||
word = optional_word {
|
|
||||||
println!("The word is: {}", word);
|
|
||||||
} else {
|
|
||||||
println!("The optional word doesn't contain anything");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
|
|
||||||
for x in 1..10 {
|
|
||||||
optional_integers_vec.push(Some(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
|
|
||||||
// You can stack `Option<T>`'s into while let and if let
|
|
||||||
integer = optional_integers_vec.pop() {
|
|
||||||
println!("current value: {}", integer);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// option3.rs
|
|
||||||
// Make me compile! Execute `rustlings hint option3` for hints
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let y: Option<Point> = Some(Point { x: 100, y: 200 });
|
|
||||||
|
|
||||||
match y {
|
|
||||||
Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y),
|
|
||||||
_ => println!("no match"),
|
|
||||||
}
|
|
||||||
y; // Fix without deleting this line.
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Primitive Types
|
|
||||||
|
|
||||||
Rust has a couple of basic types that are directly implemented into the
|
|
||||||
compiler. In this section, we'll go through the most important ones.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html)
|
|
||||||
- [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html)
|
|
|
@ -1,19 +0,0 @@
|
||||||
// primitive_types1.rs
|
|
||||||
// Fill in the rest of the line that has code missing!
|
|
||||||
// No hints, there's no tricks, just get used to typing these :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Booleans (`bool`)
|
|
||||||
|
|
||||||
let is_morning = true;
|
|
||||||
if is_morning {
|
|
||||||
println!("Good morning!");
|
|
||||||
}
|
|
||||||
|
|
||||||
let // Finish the rest of this line like the example! Or make it be false!
|
|
||||||
if is_evening {
|
|
||||||
println!("Good evening!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
// primitive_types2.rs
|
|
||||||
// Fill in the rest of the line that has code missing!
|
|
||||||
// No hints, there's no tricks, just get used to typing these :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Characters (`char`)
|
|
||||||
|
|
||||||
let my_first_initial = 'C';
|
|
||||||
if my_first_initial.is_alphabetic() {
|
|
||||||
println!("Alphabetical!");
|
|
||||||
} else if my_first_initial.is_numeric() {
|
|
||||||
println!("Numerical!");
|
|
||||||
} else {
|
|
||||||
println!("Neither alphabetic nor numeric!");
|
|
||||||
}
|
|
||||||
|
|
||||||
let // Finish this line like the example! What's your favorite character?
|
|
||||||
// Try a letter, try a number, try a special character, try a character
|
|
||||||
// from a different language than your own, try an emoji!
|
|
||||||
if your_character.is_alphabetic() {
|
|
||||||
println!("Alphabetical!");
|
|
||||||
} else if your_character.is_numeric() {
|
|
||||||
println!("Numerical!");
|
|
||||||
} else {
|
|
||||||
println!("Neither alphabetic nor numeric!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// primitive_types3.rs
|
|
||||||
// Create an array with at least 100 elements in it where the ??? is.
|
|
||||||
// Execute `rustlings hint primitive_types3` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let a = ???
|
|
||||||
|
|
||||||
if a.len() >= 100 {
|
|
||||||
println!("Wow, that's a big array!");
|
|
||||||
} else {
|
|
||||||
println!("Meh, I eat arrays like that for breakfast.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// primitive_types4.rs
|
|
||||||
// Get a slice out of Array a where the ??? is so that the test passes.
|
|
||||||
// Execute `rustlings hint primitive_types4` for hints!!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn slice_out_of_array() {
|
|
||||||
let a = [1, 2, 3, 4, 5];
|
|
||||||
|
|
||||||
let nice_slice = ???
|
|
||||||
|
|
||||||
assert_eq!([2, 3, 4], nice_slice)
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// primitive_types5.rs
|
|
||||||
// Destructure the `cat` tuple so that the println will work.
|
|
||||||
// Execute `rustlings hint primitive_types5` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let cat = ("Furry McFurson", 3.5);
|
|
||||||
let /* your pattern here */ = cat;
|
|
||||||
|
|
||||||
println!("{} is {} years old.", name, age);
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// primitive_types6.rs
|
|
||||||
// Use a tuple index to access the second element of `numbers`.
|
|
||||||
// You can put the expression for the second element where ??? is so that the test passes.
|
|
||||||
// Execute `rustlings hint primitive_types6` for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn indexing_tuple() {
|
|
||||||
let numbers = (1, 2, 3);
|
|
||||||
// Replace below ??? with the tuple indexing syntax.
|
|
||||||
let second = ???;
|
|
||||||
|
|
||||||
assert_eq!(2, second,
|
|
||||||
"This is not the 2nd number in the tuple!")
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
// quiz1.rs
|
|
||||||
// This is a quiz for the following sections:
|
|
||||||
// - Variables
|
|
||||||
// - Functions
|
|
||||||
|
|
||||||
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
|
|
||||||
// more than 40 at once, each apple only costs 1! Write a function that calculates
|
|
||||||
// the price of an order of apples given the order amount. No hints this time!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
// Put your function here!
|
|
||||||
// fn ..... {
|
|
||||||
|
|
||||||
// Don't modify this function!
|
|
||||||
#[test]
|
|
||||||
fn verify_test() {
|
|
||||||
let price1 = calculate_apple_price(35);
|
|
||||||
let price2 = calculate_apple_price(40);
|
|
||||||
let price3 = calculate_apple_price(65);
|
|
||||||
|
|
||||||
assert_eq!(70, price1);
|
|
||||||
assert_eq!(80, price2);
|
|
||||||
assert_eq!(65, price3);
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
// quiz2.rs
|
|
||||||
// This is a quiz for the following sections:
|
|
||||||
// - Strings
|
|
||||||
|
|
||||||
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
|
|
||||||
// task is to call one of these two functions on each value depending on what
|
|
||||||
// you think each value is. That is, add either `string_slice` or `string`
|
|
||||||
// before the parentheses on each line. If you're right, it will compile!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn string_slice(arg: &str) {
|
|
||||||
println!("{}", arg);
|
|
||||||
}
|
|
||||||
fn string(arg: String) {
|
|
||||||
println!("{}", arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
???("blue");
|
|
||||||
???("red".to_string());
|
|
||||||
???(String::from("hi"));
|
|
||||||
???("rust is fun!".to_owned());
|
|
||||||
???("nice weather".into());
|
|
||||||
???(format!("Interpolation {}", "Station"));
|
|
||||||
???(&String::from("abc")[0..1]);
|
|
||||||
???(" hello there ".trim());
|
|
||||||
???("Happy Monday!".to_string().replace("Mon", "Tues"));
|
|
||||||
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
// quiz3.rs
|
|
||||||
// This is a quiz for the following sections:
|
|
||||||
// - Tests
|
|
||||||
|
|
||||||
// This quiz isn't testing our function -- make it do that in such a way that
|
|
||||||
// the test passes. Then write a second test that tests that we get the result
|
|
||||||
// we expect to get when we call `times_two` with a negative number.
|
|
||||||
// No hints, you can do this :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub fn times_two(num: i32) -> i32 {
|
|
||||||
num * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn returns_twice_of_positive_numbers() {
|
|
||||||
assert_eq!(times_two(4), ???);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn returns_twice_of_negative_numbers() {
|
|
||||||
// TODO replace unimplemented!() with an assert for `times_two(-4)`
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
// quiz4.rs
|
|
||||||
// This quiz covers the sections:
|
|
||||||
// - Modules
|
|
||||||
// - Macros
|
|
||||||
|
|
||||||
// Write a macro that passes the quiz! No hints this time, you can do it!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_my_macro_world() {
|
|
||||||
assert_eq!(my_macro!("world!"), "Hello world!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_my_macro_goodbye() {
|
|
||||||
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Standard library types
|
|
||||||
|
|
||||||
This section will teach you about Box, Shared-State Concurrency and Iterators.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html)
|
|
||||||
- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html)
|
|
||||||
- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html)
|
|
||||||
- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/)
|
|
|
@ -1,47 +0,0 @@
|
||||||
// arc1.rs
|
|
||||||
// In this exercise, we are given a Vec of u32 called "numbers" with values ranging
|
|
||||||
// from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ]
|
|
||||||
// We would like to use this set of numbers within 8 different threads simultaneously.
|
|
||||||
// Each thread is going to get the sum of every eighth value, with an offset.
|
|
||||||
// The first thread (offset 0), will sum 0, 8, 16, ...
|
|
||||||
// The second thread (offset 1), will sum 1, 9, 17, ...
|
|
||||||
// The third thread (offset 2), will sum 2, 10, 18, ...
|
|
||||||
// ...
|
|
||||||
// The eighth thread (offset 7), will sum 7, 15, 23, ...
|
|
||||||
|
|
||||||
// Because we are using threads, our values need to be thread-safe. Therefore,
|
|
||||||
// we are using Arc. We need to make a change in each of the two TODOs.
|
|
||||||
|
|
||||||
|
|
||||||
// Make this code compile by filling in a value for `shared_numbers` where the
|
|
||||||
// first TODO comment is, and create an initial binding for `child_numbers`
|
|
||||||
// where the second TODO comment is. Try not to create any copies of the `numbers` Vec!
|
|
||||||
// Execute `rustlings hint arc1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#![forbid(unused_imports)] // Do not change this, (or the next) line.
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let numbers: Vec<_> = (0..100u32).collect();
|
|
||||||
let shared_numbers = // TODO
|
|
||||||
let mut joinhandles = Vec::new();
|
|
||||||
|
|
||||||
for offset in 0..8 {
|
|
||||||
let child_numbers = // TODO
|
|
||||||
joinhandles.push(thread::spawn(move || {
|
|
||||||
let mut i = offset;
|
|
||||||
let mut sum = 0;
|
|
||||||
while i < child_numbers.len() {
|
|
||||||
sum += child_numbers[i];
|
|
||||||
i += 8;
|
|
||||||
}
|
|
||||||
println!("Sum of offset {} is {}", offset, sum);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
for handle in joinhandles.into_iter() {
|
|
||||||
handle.join().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
// box1.rs
|
|
||||||
//
|
|
||||||
// At compile time, Rust needs to know how much space a type takes up. This becomes problematic
|
|
||||||
// for recursive types, where a value can have as part of itself another value of the same type.
|
|
||||||
// To get around the issue, we can use a `Box` - a smart pointer used to store data on the heap,
|
|
||||||
// which also allows us to wrap a recursive type.
|
|
||||||
//
|
|
||||||
// The recursive type we're implementing in this exercise is the `cons list` - a data structure
|
|
||||||
// frequently found in functional programming languages. Each item in a cons list contains two
|
|
||||||
// elements: the value of the current item and the next item. The last item is a value called `Nil`.
|
|
||||||
//
|
|
||||||
// Step 1: use a `Box` in the enum definition to make the code compile
|
|
||||||
// Step 2: create both empty and non-empty cons lists by replacing `unimplemented!()`
|
|
||||||
//
|
|
||||||
// Note: the tests should not be changed
|
|
||||||
//
|
|
||||||
// Execute `rustlings hint box1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
pub enum List {
|
|
||||||
Cons(i32, List),
|
|
||||||
Nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("This is an empty cons list: {:?}", create_empty_list());
|
|
||||||
println!(
|
|
||||||
"This is a non-empty cons list: {:?}",
|
|
||||||
create_non_empty_list()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_empty_list() -> List {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_non_empty_list() -> List {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_create_empty_list() {
|
|
||||||
assert_eq!(List::Nil, create_empty_list())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_create_non_empty_list() {
|
|
||||||
assert_ne!(create_empty_list(), create_non_empty_list())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// iterators1.rs
|
|
||||||
//
|
|
||||||
// Make me compile by filling in the `???`s
|
|
||||||
//
|
|
||||||
// When performing operations on elements within a collection, iterators are essential.
|
|
||||||
// This module helps you get familiar with the structure of using an iterator and
|
|
||||||
// how to go through elements within an iterable collection.
|
|
||||||
//
|
|
||||||
// Execute `rustlings hint iterators1` for hints :D
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main () {
|
|
||||||
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];
|
|
||||||
|
|
||||||
let mut my_iterable_fav_fruits = ???; // TODO: Step 1
|
|
||||||
|
|
||||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
|
|
||||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2
|
|
||||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
|
|
||||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1
|
|
||||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
|
|
||||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
// iterators2.rs
|
|
||||||
// In this exercise, you'll learn some of the unique advantages that iterators
|
|
||||||
// can offer. Follow the steps to complete the exercise.
|
|
||||||
// As always, there are hints if you execute `rustlings hint iterators2`!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
// Step 1.
|
|
||||||
// Complete the `capitalize_first` function.
|
|
||||||
// "hello" -> "Hello"
|
|
||||||
pub fn capitalize_first(input: &str) -> String {
|
|
||||||
let mut c = input.chars();
|
|
||||||
match c.next() {
|
|
||||||
None => String::new(),
|
|
||||||
Some(first) => ???,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2.
|
|
||||||
// Apply the `capitalize_first` function to a slice of string slices.
|
|
||||||
// Return a vector of strings.
|
|
||||||
// ["hello", "world"] -> ["Hello", "World"]
|
|
||||||
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
// Apply the `capitalize_first` function again to a slice of string slices.
|
|
||||||
// Return a single string.
|
|
||||||
// ["hello", " ", "world"] -> "Hello World"
|
|
||||||
pub fn capitalize_words_string(words: &[&str]) -> String {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_success() {
|
|
||||||
assert_eq!(capitalize_first("hello"), "Hello");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_empty() {
|
|
||||||
assert_eq!(capitalize_first(""), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_iterate_string_vec() {
|
|
||||||
let words = vec!["hello", "world"];
|
|
||||||
assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_iterate_into_string() {
|
|
||||||
let words = vec!["hello", " ", "world"];
|
|
||||||
assert_eq!(capitalize_words_string(&words), "Hello World");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
// iterators3.rs
|
|
||||||
// This is a bigger exercise than most of the others! You can do it!
|
|
||||||
// Here is your mission, should you choose to accept it:
|
|
||||||
// 1. Complete the divide function to get the first four tests to pass.
|
|
||||||
// 2. Get the remaining tests to pass by completing the result_with_list and
|
|
||||||
// list_of_results functions.
|
|
||||||
// Execute `rustlings hint iterators3` to get some hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum DivisionError {
|
|
||||||
NotDivisible(NotDivisibleError),
|
|
||||||
DivideByZero,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct NotDivisibleError {
|
|
||||||
dividend: i32,
|
|
||||||
divisor: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
|
|
||||||
// Otherwise, return a suitable error.
|
|
||||||
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {}
|
|
||||||
|
|
||||||
// Complete the function and return a value of the correct type so the test passes.
|
|
||||||
// Desired output: Ok([1, 11, 1426, 3])
|
|
||||||
fn result_with_list() -> () {
|
|
||||||
let numbers = vec![27, 297, 38502, 81];
|
|
||||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Complete the function and return a value of the correct type so the test passes.
|
|
||||||
// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)]
|
|
||||||
fn list_of_results() -> () {
|
|
||||||
let numbers = vec![27, 297, 38502, 81];
|
|
||||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_success() {
|
|
||||||
assert_eq!(divide(81, 9), Ok(9));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_not_divisible() {
|
|
||||||
assert_eq!(
|
|
||||||
divide(81, 6),
|
|
||||||
Err(DivisionError::NotDivisible(NotDivisibleError {
|
|
||||||
dividend: 81,
|
|
||||||
divisor: 6
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_divide_by_0() {
|
|
||||||
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_divide_0_by_something() {
|
|
||||||
assert_eq!(divide(0, 81), Ok(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_result_with_list() {
|
|
||||||
assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_list_of_results() {
|
|
||||||
assert_eq!(
|
|
||||||
format!("{:?}", list_of_results()),
|
|
||||||
"[Ok(1), Ok(11), Ok(1426), Ok(3)]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
// iterators4.rs
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub fn factorial(num: u64) -> u64 {
|
|
||||||
// Complete this function to return the factorial of num
|
|
||||||
// Do not use:
|
|
||||||
// - return
|
|
||||||
// Try not to use:
|
|
||||||
// - imperative style loops (for, while)
|
|
||||||
// - additional variables
|
|
||||||
// For an extra challenge, don't use:
|
|
||||||
// - recursion
|
|
||||||
// Execute `rustlings hint iterators4` for hints.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn factorial_of_1() {
|
|
||||||
assert_eq!(1, factorial(1));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn factorial_of_2() {
|
|
||||||
assert_eq!(2, factorial(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn factorial_of_4() {
|
|
||||||
assert_eq!(24, factorial(4));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
// iterators5.rs
|
|
||||||
|
|
||||||
// Let's define a simple model to track Rustlings exercise progress. Progress
|
|
||||||
// will be modelled using a hash map. The name of the exercise is the key and
|
|
||||||
// the progress is the value. Two counting functions were created to count the
|
|
||||||
// number of exercises with a given progress. These counting functions use
|
|
||||||
// imperative style for loops. Recreate this counting functionality using
|
|
||||||
// iterators. Only the two iterator methods (count_iterator and
|
|
||||||
// count_collection_iterator) need to be modified.
|
|
||||||
// Execute `rustlings hint iterators5` for hints.
|
|
||||||
//
|
|
||||||
// Make the code compile and the tests pass.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
||||||
enum Progress {
|
|
||||||
None,
|
|
||||||
Some,
|
|
||||||
Complete,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
|
|
||||||
let mut count = 0;
|
|
||||||
for val in map.values() {
|
|
||||||
if val == &value {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count
|
|
||||||
}
|
|
||||||
|
|
||||||
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
|
|
||||||
// map is a hashmap with String keys and Progress values.
|
|
||||||
// map = { "variables1": Complete, "from_str": None, ... }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
|
|
||||||
let mut count = 0;
|
|
||||||
for map in collection {
|
|
||||||
for val in map.values() {
|
|
||||||
if val == &value {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
count
|
|
||||||
}
|
|
||||||
|
|
||||||
fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
|
|
||||||
// collection is a slice of hashmaps.
|
|
||||||
// collection = [{ "variables1": Complete, "from_str": None, ... },
|
|
||||||
// { "variables2": Complete, ... }, ... ]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn count_complete() {
|
|
||||||
let map = get_map();
|
|
||||||
assert_eq!(3, count_iterator(&map, Progress::Complete));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn count_equals_for() {
|
|
||||||
let map = get_map();
|
|
||||||
assert_eq!(
|
|
||||||
count_for(&map, Progress::Complete),
|
|
||||||
count_iterator(&map, Progress::Complete)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn count_collection_complete() {
|
|
||||||
let collection = get_vec_map();
|
|
||||||
assert_eq!(
|
|
||||||
6,
|
|
||||||
count_collection_iterator(&collection, Progress::Complete)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn count_collection_equals_for() {
|
|
||||||
let collection = get_vec_map();
|
|
||||||
assert_eq!(
|
|
||||||
count_collection_for(&collection, Progress::Complete),
|
|
||||||
count_collection_iterator(&collection, Progress::Complete)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_map() -> HashMap<String, Progress> {
|
|
||||||
use Progress::*;
|
|
||||||
|
|
||||||
let mut map = HashMap::new();
|
|
||||||
map.insert(String::from("variables1"), Complete);
|
|
||||||
map.insert(String::from("functions1"), Complete);
|
|
||||||
map.insert(String::from("hashmap1"), Complete);
|
|
||||||
map.insert(String::from("arc1"), Some);
|
|
||||||
map.insert(String::from("as_ref_mut"), None);
|
|
||||||
map.insert(String::from("from_str"), None);
|
|
||||||
|
|
||||||
map
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_vec_map() -> Vec<HashMap<String, Progress>> {
|
|
||||||
use Progress::*;
|
|
||||||
|
|
||||||
let map = get_map();
|
|
||||||
|
|
||||||
let mut other = HashMap::new();
|
|
||||||
other.insert(String::from("variables2"), Complete);
|
|
||||||
other.insert(String::from("functions2"), Complete);
|
|
||||||
other.insert(String::from("if1"), Complete);
|
|
||||||
other.insert(String::from("from_into"), None);
|
|
||||||
other.insert(String::from("try_from_into"), None);
|
|
||||||
|
|
||||||
vec![map, other]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Strings
|
|
||||||
|
|
||||||
Rust has two string types, a string slice (`&str`) and an owned string (`String`).
|
|
||||||
We're not going to dictate when you should use which one, but we'll show you how
|
|
||||||
to identify and create them, as well as use them.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)
|
|
|
@ -1,14 +0,0 @@
|
||||||
// strings1.rs
|
|
||||||
// Make me compile without changing the function signature!
|
|
||||||
// Execute `rustlings hint strings1` for hints ;)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let answer = current_favorite_color();
|
|
||||||
println!("My current favorite color is {}", answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_favorite_color() -> String {
|
|
||||||
"blue"
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// strings2.rs
|
|
||||||
// Make me compile without changing the function signature!
|
|
||||||
// Execute `rustlings hint strings2` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let word = String::from("green"); // Try not changing this line :)
|
|
||||||
if is_a_color_word(word) {
|
|
||||||
println!("That is a color word I know!");
|
|
||||||
} else {
|
|
||||||
println!("That is not a color word I know.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_a_color_word(attempt: &str) -> bool {
|
|
||||||
attempt == "green" || attempt == "blue" || attempt == "red"
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
# Structs
|
|
||||||
|
|
||||||
Rust has three struct types: a classic C struct, a tuple struct, and a unit struct.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
|
|
||||||
- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
|
|
|
@ -1,45 +0,0 @@
|
||||||
// structs1.rs
|
|
||||||
// Address all the TODOs to make the tests pass!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
struct ColorClassicStruct {
|
|
||||||
// TODO: Something goes here
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ColorTupleStruct(/* TODO: Something goes here */);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct UnitStruct;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn classic_c_structs() {
|
|
||||||
// TODO: Instantiate a classic c struct!
|
|
||||||
// let green =
|
|
||||||
|
|
||||||
assert_eq!(green.name, "green");
|
|
||||||
assert_eq!(green.hex, "#00FF00");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn tuple_structs() {
|
|
||||||
// TODO: Instantiate a tuple struct!
|
|
||||||
// let green =
|
|
||||||
|
|
||||||
assert_eq!(green.0, "green");
|
|
||||||
assert_eq!(green.1, "#00FF00");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unit_structs() {
|
|
||||||
// TODO: Instantiate a unit struct!
|
|
||||||
// let unit_struct =
|
|
||||||
let message = format!("{:?}s are fun!", unit_struct);
|
|
||||||
|
|
||||||
assert_eq!(message, "UnitStructs are fun!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
// structs2.rs
|
|
||||||
// Address all the TODOs to make the tests pass!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Order {
|
|
||||||
name: String,
|
|
||||||
year: u32,
|
|
||||||
made_by_phone: bool,
|
|
||||||
made_by_mobile: bool,
|
|
||||||
made_by_email: bool,
|
|
||||||
item_number: u32,
|
|
||||||
count: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_order_template() -> Order {
|
|
||||||
Order {
|
|
||||||
name: String::from("Bob"),
|
|
||||||
year: 2019,
|
|
||||||
made_by_phone: false,
|
|
||||||
made_by_mobile: false,
|
|
||||||
made_by_email: true,
|
|
||||||
item_number: 123,
|
|
||||||
count: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn your_order() {
|
|
||||||
let order_template = create_order_template();
|
|
||||||
// TODO: Create your own order using the update syntax and template above!
|
|
||||||
// let your_order =
|
|
||||||
assert_eq!(your_order.name, "Hacker in Rust");
|
|
||||||
assert_eq!(your_order.year, order_template.year);
|
|
||||||
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
|
|
||||||
assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
|
|
||||||
assert_eq!(your_order.made_by_email, order_template.made_by_email);
|
|
||||||
assert_eq!(your_order.item_number, order_template.item_number);
|
|
||||||
assert_eq!(your_order.count, 1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
// structs3.rs
|
|
||||||
// Structs contain data, but can also have logic. In this exercise we have
|
|
||||||
// defined the Package struct and we want to test some logic attached to it.
|
|
||||||
// Make the code compile and the tests pass!
|
|
||||||
// If you have issues execute `rustlings hint structs3`
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Package {
|
|
||||||
sender_country: String,
|
|
||||||
recipient_country: String,
|
|
||||||
weight_in_grams: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Package {
|
|
||||||
fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
|
|
||||||
if weight_in_grams <= 0 {
|
|
||||||
// Something goes here...
|
|
||||||
} else {
|
|
||||||
return Package {
|
|
||||||
sender_country,
|
|
||||||
recipient_country,
|
|
||||||
weight_in_grams,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_international(&self) -> ??? {
|
|
||||||
// Something goes here...
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_fees(&self, cents_per_gram: i32) -> ??? {
|
|
||||||
// Something goes here...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn fail_creating_weightless_package() {
|
|
||||||
let sender_country = String::from("Spain");
|
|
||||||
let recipient_country = String::from("Austria");
|
|
||||||
|
|
||||||
Package::new(sender_country, recipient_country, -2210);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn create_international_package() {
|
|
||||||
let sender_country = String::from("Spain");
|
|
||||||
let recipient_country = String::from("Russia");
|
|
||||||
|
|
||||||
let package = Package::new(sender_country, recipient_country, 1200);
|
|
||||||
|
|
||||||
assert!(package.is_international());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn create_local_package() {
|
|
||||||
let sender_country = String::from("Canada");
|
|
||||||
let recipient_country = sender_country.clone();
|
|
||||||
|
|
||||||
let package = Package::new(sender_country, recipient_country, 1200);
|
|
||||||
|
|
||||||
assert!(!package.is_international());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn calculate_transport_fees() {
|
|
||||||
let sender_country = String::from("Spain");
|
|
||||||
let recipient_country = String::from("Spain");
|
|
||||||
|
|
||||||
let cents_per_gram = ???;
|
|
||||||
|
|
||||||
let package = Package::new(sender_country, recipient_country, 1500);
|
|
||||||
|
|
||||||
assert_eq!(package.get_fees(cents_per_gram), 4500);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
# Tests
|
|
||||||
|
|
||||||
Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass!
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html)
|
|
|
@ -1,17 +0,0 @@
|
||||||
// tests1.rs
|
|
||||||
// Tests are important to ensure that your code does what you think it should do.
|
|
||||||
// Tests can be run on this file with the following command:
|
|
||||||
// rustlings run tests1
|
|
||||||
|
|
||||||
// This test has a problem with it -- make the test compile! Make the test
|
|
||||||
// pass! Make the test fail! Execute `rustlings hint tests1` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn you_can_assert() {
|
|
||||||
assert!();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// tests2.rs
|
|
||||||
// This test has a problem with it -- make the test compile! Make the test
|
|
||||||
// pass! Make the test fail! Execute `rustlings hint tests2` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn you_can_assert_eq() {
|
|
||||||
assert_eq!();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// tests3.rs
|
|
||||||
// This test isn't testing our function -- make it do that in such a way that
|
|
||||||
// the test passes. Then write a second test that tests whether we get the result
|
|
||||||
// we expect to get when we call `is_even(5)`.
|
|
||||||
// Execute `rustlings hint tests3` for hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub fn is_even(num: i32) -> bool {
|
|
||||||
num % 2 == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_true_when_even() {
|
|
||||||
assert!();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_false_when_odd() {
|
|
||||||
assert!();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Threads
|
|
||||||
|
|
||||||
In most current operating systems, an executed program’s code is run in a process, and the operating system manages multiple processes at once.
|
|
||||||
Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html)
|
|
||||||
- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html)
|
|
|
@ -1,32 +0,0 @@
|
||||||
// threads1.rs
|
|
||||||
// Make this compile! Execute `rustlings hint threads1` for hints :)
|
|
||||||
// The idea is the thread spawned on line 22 is completing jobs while the main thread is
|
|
||||||
// monitoring progress until 10 jobs are completed. Because of the difference between the
|
|
||||||
// spawned threads' sleep time, and the waiting threads sleep time, when you see 6 lines
|
|
||||||
// of "waiting..." and the program ends without timing out when running,
|
|
||||||
// you've got it :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
struct JobStatus {
|
|
||||||
jobs_completed: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let status = Arc::new(JobStatus { jobs_completed: 0 });
|
|
||||||
let status_shared = status.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
for _ in 0..10 {
|
|
||||||
thread::sleep(Duration::from_millis(250));
|
|
||||||
status_shared.jobs_completed += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
while status.jobs_completed < 10 {
|
|
||||||
println!("waiting... ");
|
|
||||||
thread::sleep(Duration::from_millis(500));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
# Traits
|
|
||||||
|
|
||||||
A trait is a collection of methods.
|
|
||||||
|
|
||||||
Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`.
|
|
||||||
|
|
||||||
In this way, traits are somewhat similar to Java interfaces and C++ abstract classes.
|
|
||||||
|
|
||||||
Some additional common Rust traits include:
|
|
||||||
- `Clone` (the `clone` method)
|
|
||||||
- `Display` (which allows formatted display via `{}`)
|
|
||||||
- `Debug` (which allows formatted display via `{:?}`)
|
|
||||||
|
|
||||||
Because traits indicate shared behavior between data types, they are useful when writing generics.
|
|
||||||
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html)
|
|
|
@ -1,43 +0,0 @@
|
||||||
// traits1.rs
|
|
||||||
// Time to implement some traits!
|
|
||||||
//
|
|
||||||
// Your task is to implement the trait
|
|
||||||
// `AppendBar' for the type `String'.
|
|
||||||
//
|
|
||||||
// The trait AppendBar has only one function,
|
|
||||||
// which appends "Bar" to any object
|
|
||||||
// implementing this trait.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
trait AppendBar {
|
|
||||||
fn append_bar(self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppendBar for String {
|
|
||||||
//Add your code here
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let s = String::from("Foo");
|
|
||||||
let s = s.append_bar();
|
|
||||||
println!("s: {}", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_FooBar() {
|
|
||||||
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_BarBar() {
|
|
||||||
assert_eq!(
|
|
||||||
String::from("").append_bar().append_bar(),
|
|
||||||
String::from("BarBar")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// traits2.rs
|
|
||||||
//
|
|
||||||
// Your task is to implement the trait
|
|
||||||
// `AppendBar' for a vector of strings.
|
|
||||||
//
|
|
||||||
// To implement this trait, consider for
|
|
||||||
// a moment what it means to 'append "Bar"'
|
|
||||||
// to a vector of strings.
|
|
||||||
//
|
|
||||||
// No boiler plate code this time,
|
|
||||||
// you can do this!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
trait AppendBar {
|
|
||||||
fn append_bar(self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Add your code here
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_vec_pop_eq_bar() {
|
|
||||||
let mut foo = vec![String::from("Foo")].append_bar();
|
|
||||||
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
|
|
||||||
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Variables
|
|
||||||
|
|
||||||
In Rust, variables are immutable by default.
|
|
||||||
When a variable is immutable, once a value is bound to a name, you can’t change that value.
|
|
||||||
You can make them mutable by adding mut in front of the variable name.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html)
|
|
|
@ -1,14 +0,0 @@
|
||||||
// variables1.rs
|
|
||||||
// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)
|
|
||||||
|
|
||||||
// About this `I AM NOT DONE` thing:
|
|
||||||
// We sometimes encourage you to keep trying things on a given exercise,
|
|
||||||
// even after you already figured it out. If you got everything working and
|
|
||||||
// feel ready for the next exercise, remove the `I AM NOT DONE` comment below.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
x = 5;
|
|
||||||
println!("x has the value {}", x);
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// variables2.rs
|
|
||||||
// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x;
|
|
||||||
if x == 10 {
|
|
||||||
println!("Ten!");
|
|
||||||
} else {
|
|
||||||
println!("Not ten!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// variables3.rs
|
|
||||||
// Make me compile! Execute the command `rustlings hint variables3` if you want a hint :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x = 3;
|
|
||||||
println!("Number {}", x);
|
|
||||||
x = 5; // don't change this line
|
|
||||||
println!("Number {}", x);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
// variables4.rs
|
|
||||||
// Make me compile! Execute the command `rustlings hint variables4` if you want a hint :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x: i32;
|
|
||||||
println!("Number {}", x);
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// variables5.rs
|
|
||||||
// Make me compile! Execute the command `rustlings hint variables5` if you want a hint :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let number = "T-H-R-E-E"; // don't change this line
|
|
||||||
println!("Spell a Number : {}", number);
|
|
||||||
number = 3;
|
|
||||||
println!("Number plus two is : {}", number + 2);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
// variables6.rs
|
|
||||||
// Make me compile! Execute the command `rustlings hint variables6` if you want a hint :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
const NUMBER = 3;
|
|
||||||
fn main() {
|
|
||||||
println!("Number {}", NUMBER);
|
|
||||||
}
|
|
Loading…
Reference in a new issue