summaryrefslogtreecommitdiff
path: root/exercises
diff options
context:
space:
mode:
Diffstat (limited to 'exercises')
-rw-r--r--exercises/README.md4
-rw-r--r--exercises/advanced_errors/advanced_errs1.rs98
-rw-r--r--exercises/advanced_errors/advanced_errs2.rs202
-rw-r--r--exercises/clippy/clippy1.rs16
-rw-r--r--exercises/collections/README.md1
-rw-r--r--exercises/conversions/from_str.rs58
-rw-r--r--exercises/conversions/try_from_into.rs74
-rw-r--r--exercises/error_handling/errors1.rs1
-rw-r--r--exercises/error_handling/errors4.rs (renamed from exercises/error_handling/result1.rs)4
-rw-r--r--exercises/error_handling/errors5.rs53
-rw-r--r--exercises/error_handling/errors6.rs95
-rw-r--r--exercises/error_handling/errorsn.rs117
-rw-r--r--exercises/generics/generics1.rs2
-rw-r--r--exercises/generics/generics2.rs2
-rw-r--r--exercises/intro/README.md8
-rw-r--r--exercises/intro/intro1.rs23
-rw-r--r--exercises/intro/intro2.rs9
-rw-r--r--exercises/modules/README.md2
-rw-r--r--exercises/modules/modules1.rs6
-rw-r--r--exercises/modules/modules2.rs8
-rw-r--r--exercises/modules/modules3.rs18
-rw-r--r--exercises/move_semantics/move_semantics5.rs15
-rw-r--r--exercises/option/README.md2
-rw-r--r--exercises/option/option1.rs2
-rw-r--r--exercises/option/option3.rs19
-rw-r--r--exercises/quiz1.rs5
-rw-r--r--exercises/standard_library_types/iterators1.rs6
-rw-r--r--exercises/standard_library_types/iterators5.rs6
-rw-r--r--exercises/structs/structs3.rs10
-rw-r--r--exercises/traits/traits1.rs4
-rw-r--r--exercises/variables/variables1.rs8
-rw-r--r--exercises/variables/variables5.rs2
32 files changed, 691 insertions, 189 deletions
diff --git a/exercises/README.md b/exercises/README.md
index 0c71524..73754db 100644
--- a/exercises/README.md
+++ b/exercises/README.md
@@ -9,8 +9,8 @@
| primitive_types | §4.3 |
| structs | §5.1 |
| enums | §6 |
-| modules | §7.2 |
-| collections | §8.1 |
+| modules | §7 |
+| collections | §8.1, §8.3 |
| strings | §8.2 |
| error_handling | §9 |
| generics | §10 |
diff --git a/exercises/advanced_errors/advanced_errs1.rs b/exercises/advanced_errors/advanced_errs1.rs
new file mode 100644
index 0000000..4bc7b63
--- /dev/null
+++ b/exercises/advanced_errors/advanced_errs1.rs
@@ -0,0 +1,98 @@
+// advanced_errs1.rs
+
+// Remember back in errors6, we had multiple mapping functions so that we
+// could translate lower-level errors into our custom error type using
+// `map_err()`? What if we could use the `?` operator directly instead?
+
+// Make this code compile! Execute `rustlings hint advanced_errs1` for
+// hints :)
+
+// I AM NOT DONE
+
+use std::num::ParseIntError;
+use std::str::FromStr;
+
+// This is a custom error type that we will be using in the `FromStr`
+// implementation.
+#[derive(PartialEq, Debug)]
+enum ParsePosNonzeroError {
+ Creation(CreationError),
+ ParseInt(ParseIntError),
+}
+
+impl From<CreationError> for ParsePosNonzeroError {
+ fn from(e: CreationError) -> Self {
+ // TODO: complete this implementation so that the `?` operator will
+ // work for `CreationError`
+ }
+}
+
+// TODO: implement another instance of the `From` trait here so that the
+// `?` operator will work in the other place in the `FromStr`
+// implementation below.
+
+// Don't change anything below this line.
+
+impl FromStr for PositiveNonzeroInteger {
+ type Err = ParsePosNonzeroError;
+ fn from_str(s: &str) -> Result<PositiveNonzeroInteger, Self::Err> {
+ let x: i64 = s.parse()?;
+ Ok(PositiveNonzeroInteger::new(x)?)
+ }
+}
+
+#[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!(
+ PositiveNonzeroInteger::from_str("not a number"),
+ Err(ParsePosNonzeroError::ParseInt(_))
+ ));
+ }
+
+ #[test]
+ fn test_negative() {
+ assert_eq!(
+ PositiveNonzeroInteger::from_str("-555"),
+ Err(ParsePosNonzeroError::Creation(CreationError::Negative))
+ );
+ }
+
+ #[test]
+ fn test_zero() {
+ assert_eq!(
+ PositiveNonzeroInteger::from_str("0"),
+ Err(ParsePosNonzeroError::Creation(CreationError::Zero))
+ );
+ }
+
+ #[test]
+ fn test_positive() {
+ let x = PositiveNonzeroInteger::new(42);
+ assert!(x.is_ok());
+ assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap()));
+ }
+}
diff --git a/exercises/advanced_errors/advanced_errs2.rs b/exercises/advanced_errors/advanced_errs2.rs
new file mode 100644
index 0000000..54e669f
--- /dev/null
+++ b/exercises/advanced_errors/advanced_errs2.rs
@@ -0,0 +1,202 @@
+// advanced_errs2.rs
+
+// This exercise demonstrates a few traits that are useful for custom error
+// types to implement, especially so that other code can consume the custom
+// error type more usefully.
+
+// Make this compile, and make the tests pass!
+// Execute `rustlings hint advanced_errs2` for hints.
+
+// Steps:
+// 1. Implement a missing trait so that `main()` will compile.
+// 2. Complete the partial implementation of `From` for
+// `ParseClimateError`.
+// 3. Handle the missing error cases in the `FromStr` implementation for
+// `Climate`.
+// 4. Complete the partial implementation of `Display` for
+// `ParseClimateError`.
+
+// I AM NOT DONE
+
+use std::error::Error;
+use std::fmt::{self, Display, Formatter};
+use std::num::{ParseFloatError, ParseIntError};
+use std::str::FromStr;
+
+// This is the custom error type that we will be using for the parser for
+// `Climate`.
+#[derive(Debug, PartialEq)]
+enum ParseClimateError {
+ Empty,
+ BadLen,
+ NoCity,
+ ParseInt(ParseIntError),
+ ParseFloat(ParseFloatError),
+}
+
+// This `From` implementation allows the `?` operator to work on
+// `ParseIntError` values.
+impl From<ParseIntError> for ParseClimateError {
+ fn from(e: ParseIntError) -> Self {
+ Self::ParseInt(e)
+ }
+}
+
+// This `From` implementation allows the `?` operator to work on
+// `ParseFloatError` values.
+impl From<ParseFloatError> for ParseClimateError {
+ fn from(e: ParseFloatError) -> Self {
+ // TODO: Complete this function
+ }
+}
+
+// TODO: Implement a missing trait so that `main()` below will compile. It
+// is not necessary to implement any methods inside the missing trait.
+
+// The `Display` trait allows for other code to obtain the error formatted
+// as a user-visible string.
+impl Display for ParseClimateError {
+ // TODO: Complete this function so that it produces the correct strings
+ // for each error variant.
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ // Imports the variants to make the following code more compact.
+ use ParseClimateError::*;
+ match self {
+ NoCity => write!(f, "no city name"),
+ ParseFloat(e) => write!(f, "error parsing temperature: {}", e),
+ }
+ }
+}
+
+#[derive(Debug, PartialEq)]
+struct Climate {
+ city: String,
+ year: u32,
+ temp: f32,
+}
+
+// Parser for `Climate`.
+// 1. Split the input string into 3 fields: city, year, temp.
+// 2. Return an error if the string is empty or has the wrong number of
+// fields.
+// 3. Return an error if the city name is empty.
+// 4. Parse the year as a `u32` and return an error if that fails.
+// 5. Parse the temp as a `f32` and return an error if that fails.
+// 6. Return an `Ok` value containing the completed `Climate` value.
+impl FromStr for Climate {
+ type Err = ParseClimateError;
+ // TODO: Complete this function by making it handle the missing error
+ // cases.
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let v: Vec<_> = s.split(',').collect();
+ let (city, year, temp) = match &v[..] {
+ [city, year, temp] => (city.to_string(), year, temp),
+ _ => return Err(ParseClimateError::BadLen),
+ };
+ let year: u32 = year.parse()?;
+ let temp: f32 = temp.parse()?;
+ Ok(Climate { city, year, temp })
+ }
+}
+
+// Don't change anything below this line (other than to enable ignored
+// tests).
+
+fn main() -> Result<(), Box<dyn Error>> {
+ println!("{:?}", "Hong Kong,1999,25.7".parse::<Climate>()?);
+ println!("{:?}", "".parse::<Climate>()?);
+ Ok(())
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ #[test]
+ fn test_empty() {
+ let res = "".parse::<Climate>();
+ assert_eq!(res, Err(ParseClimateError::Empty));
+ assert_eq!(res.unwrap_err().to_string(), "empty input");
+ }
+ #[test]
+ fn test_short() {
+ let res = "Boston,1991".parse::<Climate>();
+ assert_eq!(res, Err(ParseClimateError::BadLen));
+ assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
+ }
+ #[test]
+ fn test_long() {
+ let res = "Paris,1920,17.2,extra".parse::<Climate>();
+ assert_eq!(res, Err(ParseClimateError::BadLen));
+ assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
+ }
+ #[test]
+ fn test_no_city() {
+ let res = ",1997,20.5".parse::<Climate>();
+ assert_eq!(res, Err(ParseClimateError::NoCity));
+ assert_eq!(res.unwrap_err().to_string(), "no city name");
+ }
+ #[test]
+ fn test_parse_int_neg() {
+ let res = "Barcelona,-25,22.3".parse::<Climate>();
+ assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
+ let err = res.unwrap_err();
+ if let ParseClimateError::ParseInt(ref inner) = err {
+ assert_eq!(
+ err.to_string(),
+ format!("error parsing year: {}", inner.to_string())
+ );
+ } else {
+ unreachable!();
+ };
+ }
+ #[test]
+ fn test_parse_int_bad() {
+ let res = "Beijing,foo,15.0".parse::<Climate>();
+ assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
+ let err = res.unwrap_err();
+ if let ParseClimateError::ParseInt(ref inner) = err {
+ assert_eq!(
+ err.to_string(),
+ format!("error parsing year: {}", inner.to_string())
+ );
+ } else {
+ unreachable!();
+ };
+ }
+ #[test]
+ fn test_parse_float() {
+ let res = "Manila,2001,bar".parse::<Climate>();
+ assert!(matches!(res, Err(ParseClimateError::ParseFloat(_))));
+ let err = res.unwrap_err();
+ if let ParseClimateError::ParseFloat(ref inner) = err {
+ assert_eq!(
+ err.to_string(),
+ format!("error parsing temperature: {}", inner.to_string())
+ );
+ } else {
+ unreachable!();
+ };
+ }
+ #[test]
+ fn test_parse_good() {
+ let res = "Munich,2015,23.1".parse::<Climate>();
+ assert_eq!(
+ res,
+ Ok(Climate {
+ city: "Munich".to_string(),
+ year: 2015,
+ temp: 23.1,
+ })
+ );
+ }
+ #[test]
+ #[ignore]
+ fn test_downcast() {
+ let res = "São Paulo,-21,28.5".parse::<Climate>();
+ assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
+ let err = res.unwrap_err();
+ let inner: Option<&(dyn Error + 'static)> = err.source();
+ assert!(inner.is_some());
+ assert!(inner.unwrap().is::<ParseIntError>());
+ }
+}
diff --git a/exercises/clippy/clippy1.rs b/exercises/clippy/clippy1.rs
index bdb5dd2..c5f84a9 100644
--- a/exercises/clippy/clippy1.rs
+++ b/exercises/clippy/clippy1.rs
@@ -8,10 +8,16 @@
// I AM NOT DONE
+use std::f32;
+
fn main() {
- let x = 1.2331f64;
- let y = 1.2332f64;
- if y != x {
- println!("Success!");
- }
+ let pi = 3.14f32;
+ let radius = 5.00f32;
+
+ let area = pi * f32::powi(radius, 2);
+
+ println!(
+ "The area of a circle with radius {:.2} is {:.5}!",
+ radius, area
+ )
}
diff --git a/exercises/collections/README.md b/exercises/collections/README.md
index 0291bc8..b6d62ac 100644
--- a/exercises/collections/README.md
+++ b/exercises/collections/README.md
@@ -20,3 +20,4 @@ structures that are used very often in Rust programs:
## Further information
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html)
+- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
diff --git a/exercises/conversions/from_str.rs b/exercises/conversions/from_str.rs
index 4beebac..ece0b3c 100644
--- a/exercises/conversions/from_str.rs
+++ b/exercises/conversions/from_str.rs
@@ -1,16 +1,31 @@
-// This does practically the same thing that TryFrom<&str> does.
+// from_str.rs
+// This is similar to from_into.rs, but this time we'll implement `FromStr`
+// and return errors instead of falling back to a default value.
// 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::num::ParseIntError;
use std::str::FromStr;
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: usize,
}
+// We will use this error type for the `FromStr` implementation.
+#[derive(Debug, PartialEq)]
+enum ParsePersonError {
+ // Empty input string
+ Empty,
+ // Incorrect number of fields
+ BadLen,
+ // Empty name field
+ NoName,
+ // Wrapped error from parse::<usize>()
+ ParseInt(ParseIntError),
+}
+
// I AM NOT DONE
// Steps:
@@ -20,11 +35,11 @@ struct Person {
// 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
+// 6. 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>;
+ type Err = ParsePersonError;
fn from_str(s: &str) -> Result<Person, Self::Err> {
}
}
@@ -40,7 +55,7 @@ mod tests {
#[test]
fn empty_input() {
- assert!("".parse::<Person>().is_err());
+ assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));
}
#[test]
fn good_input() {
@@ -52,41 +67,56 @@ mod tests {
}
#[test]
fn missing_age() {
- assert!("John,".parse::<Person>().is_err());
+ assert!(matches!(
+ "John,".parse::<Person>(),
+ Err(ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn invalid_age() {
- assert!("John,twenty".parse::<Person>().is_err());
+ assert!(matches!(
+ "John,twenty".parse::<Person>(),
+ Err(ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn missing_comma_and_age() {
- assert!("John".parse::<Person>().is_err());
+ assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));
}
#[test]
fn missing_name() {
- assert!(",1".parse::<Person>().is_err());
+ assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));
}
#[test]
fn missing_name_and_age() {
- assert!(",".parse::<Person>().is_err());
+ assert!(matches!(
+ ",".parse::<Person>(),
+ Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn missing_name_and_invalid_age() {
- assert!(",one".parse::<Person>().is_err());
+ assert!(matches!(
+ ",one".parse::<Person>(),
+ Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn trailing_comma() {
- assert!("John,32,".parse::<Person>().is_err());
+ assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));
}
#[test]
fn trailing_comma_and_some_string() {
- assert!("John,32,man".parse::<Person>().is_err());
+ assert_eq!(
+ "John,32,man".parse::<Person>(),
+ Err(ParsePersonError::BadLen)
+ );
}
}
diff --git a/exercises/conversions/try_from_into.rs b/exercises/conversions/try_from_into.rs
index c0b5d98..b8ec445 100644
--- a/exercises/conversions/try_from_into.rs
+++ b/exercises/conversions/try_from_into.rs
@@ -1,9 +1,9 @@
+// try_from_into.rs
// 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 {
@@ -12,12 +12,21 @@ struct Color {
blue: u8,
}
+// We will use this error type for these `TryFrom` conversions.
+#[derive(Debug, PartialEq)]
+enum IntoColorError {
+ // Incorrect length of slice
+ BadLen,
+ // Integer conversion error
+ IntConversion,
+}
+
// 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.
+// 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!
@@ -25,20 +34,23 @@ struct Color {
// 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> {}
+ type Error = IntoColorError;
+ 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> {}
+ type Error = IntoColorError;
+ 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> {}
+ type Error = IntoColorError;
+ fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
+ }
}
fn main() {
@@ -46,15 +58,15 @@ fn main() {
let c1 = Color::try_from((183, 65, 14));
println!("{:?}", c1);
- // Since From is implemented for Color, we should be able to use Into
+ // Since TryFrom is implemented for Color, we should be able to use TryInto
let c2: Result<Color, _> = [183, 65, 14].try_into();
println!("{:?}", c2);
let v = vec![183, 65, 14];
- // With slice we should use `from` function
+ // With slice we should use `try_from` function
let c3 = Color::try_from(&v[..]);
println!("{:?}", c3);
- // or take slice within round brackets and use Into
+ // or take slice within round brackets and use TryInto
let c4: Result<Color, _> = (&v[..]).try_into();
println!("{:?}", c4);
}
@@ -65,15 +77,24 @@ mod tests {
#[test]
fn test_tuple_out_of_range_positive() {
- assert!(Color::try_from((256, 1000, 10000)).is_err());
+ assert_eq!(
+ Color::try_from((256, 1000, 10000)),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_tuple_out_of_range_negative() {
- assert!(Color::try_from((-1, -10, -256)).is_err());
+ assert_eq!(
+ Color::try_from((-1, -10, -256)),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_tuple_sum() {
- assert!(Color::try_from((-1, 255, 255)).is_err());
+ assert_eq!(
+ Color::try_from((-1, 255, 255)),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_tuple_correct() {
@@ -91,17 +112,17 @@ mod tests {
#[test]
fn test_array_out_of_range_positive() {
let c: Result<Color, _> = [1000, 10000, 256].try_into();
- assert!(c.is_err());
+ assert_eq!(c, Err(IntoColorError::IntConversion));
}
#[test]
fn test_array_out_of_range_negative() {
let c: Result<Color, _> = [-10, -256, -1].try_into();
- assert!(c.is_err());
+ assert_eq!(c, Err(IntoColorError::IntConversion));
}
#[test]
fn test_array_sum() {
let c: Result<Color, _> = [-1, 255, 255].try_into();
- assert!(c.is_err());
+ assert_eq!(c, Err(IntoColorError::IntConversion));
}
#[test]
fn test_array_correct() {
@@ -119,17 +140,26 @@ mod tests {
#[test]
fn test_slice_out_of_range_positive() {
let arr = [10000, 256, 1000];
- assert!(Color::try_from(&arr[..]).is_err());
+ assert_eq!(
+ Color::try_from(&arr[..]),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_slice_out_of_range_negative() {
let arr = [-256, -1, -10];
- assert!(Color::try_from(&arr[..]).is_err());
+ assert_eq!(
+ Color::try_from(&arr[..]),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_slice_sum() {
let arr = [-1, 255, 255];
- assert!(Color::try_from(&arr[..]).is_err());
+ assert_eq!(
+ Color::try_from(&arr[..]),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_slice_correct() {
@@ -148,11 +178,11 @@ mod tests {
#[test]
fn test_slice_excess_length() {
let v = vec![0, 0, 0, 0];
- assert!(Color::try_from(&v[..]).is_err());
+ assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
}
#[test]
fn test_slice_insufficient_length() {
let v = vec![0, 0];
- assert!(Color::try_from(&v[..]).is_err());
+ assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
}
}
diff --git a/exercises/error_handling/errors1.rs b/exercises/error_handling/errors1.rs
index 9c24d85..5844a49 100644
--- a/exercises/error_handling/errors1.rs
+++ b/exercises/error_handling/errors1.rs
@@ -36,6 +36,7 @@ mod tests {
fn explains_why_generating_nametag_text_fails() {
assert_eq!(
generate_nametag_text("".into()),
+ // Don't change this line
Err("`name` was empty; it must be nonempty.".into())
);
}
diff --git a/exercises/error_handling/result1.rs b/exercises/error_handling/errors4.rs
index b978001..0685c37 100644
--- a/exercises/error_handling/result1.rs
+++ b/exercises/error_handling/errors4.rs
@@ -1,5 +1,5 @@
-// result1.rs
-// Make this test pass! Execute `rustlings hint result1` for hints :)
+// errors4.rs
+// Make this test pass! Execute `rustlings hint errors4` for hints :)
// I AM NOT DONE
diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs
new file mode 100644
index 0000000..365a869
--- /dev/null
+++ b/exercises/error_handling/errors5.rs
@@ -0,0 +1,53 @@
+// 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 {}
diff --git a/exercises/error_handling/errors6.rs b/exercises/error_handling/errors6.rs
new file mode 100644
index 0000000..0f6b27a
--- /dev/null
+++ b/exercises/error_handling/errors6.rs
@@ -0,0 +1,95 @@
+// 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()));
+ }
+}
diff --git a/exercises/error_handling/errorsn.rs b/exercises/error_handling/errorsn.rs
deleted file mode 100644
index 5fe212b..0000000
--- a/exercises/error_handling/errorsn.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-// errorsn.rs
-// This is a bigger error exercise than the previous ones!
-// You can do it! :)
-//
-// Edit the `read_and_validate` function ONLY. Don't create any Errors
-// that do not already exist.
-//
-// So many things could go wrong!
-//
-// - Reading from stdin could produce an io::Error
-// - Parsing the input could produce a num::ParseIntError
-// - Validating the input could produce a CreationError (defined below)
-//
-// How can we lump these errors into one general error? That is, what
-// type goes where the question marks are, and how do we return
-// that type from the body of read_and_validate?
-//
-// Execute `rustlings hint errorsn` for hints :)
-
-// I AM NOT DONE
-
-use std::error;
-use std::fmt;
-use std::io;
-
-// PositiveNonzeroInteger is a struct defined below the tests.
-fn read_and_validate(b: &mut dyn io::BufRead) -> Result<PositiveNonzeroInteger, ???> {
- let mut line = String::new();
- b.read_line(&mut line);
- let num: i64 = line.trim().parse();
- let answer = PositiveNonzeroInteger::new(num);
- answer
-}
-
-//
-// Nothing below this needs to be modified
-//
-
-// This is a test helper function that turns a &str into a BufReader.
-fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<dyn error::Error>> {
- let mut b = io::BufReader::new(s.as_bytes());
- read_and_validate(&mut b)
-}
-
-#[test]
-fn test_success() {
- let x = test_with_str("42\n");
- assert_eq!(PositiveNonzeroInteger(42), x.unwrap());
-}
-
-#[test]
-fn test_not_num() {
- let x = test_with_str("eleven billion\n");
- assert!(x.is_err());
-}
-
-#[test]
-fn test_non_positive() {
- let x = test_with_str("-40\n");
- assert!(x.is_err());
-}
-
-#[test]
-fn test_ioerror() {
- struct Broken;
- impl io::Read for Broken {
- fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
- Err(io::Error::new(io::ErrorKind::BrokenPipe, "uh-oh!"))
- }
- }
- let mut b = io::BufReader::new(Broken);
- assert!(read_and_validate(&mut b).is_err());
- assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string());
-}
-
-#[derive(PartialEq, Debug)]
-struct PositiveNonzeroInteger(u64);
-
-impl PositiveNonzeroInteger {
- fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
- if value == 0 {
- Err(CreationError::Zero)
- } else if value < 0 {
- Err(CreationError::Negative)
- } else {
- Ok(PositiveNonzeroInteger(value as u64))
- }
- }
-}
-
-#[test]
-fn test_positive_nonzero_integer_creation() {
- assert!(PositiveNonzeroInteger::new(10).is_ok());
- assert_eq!(
- Err(CreationError::Negative),
- PositiveNonzeroInteger::new(-10)
- );
- assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
-}
-
-#[derive(PartialEq, Debug)]
-enum CreationError {
- Negative,
- Zero,
-}
-
-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 {}
diff --git a/exercises/generics/generics1.rs b/exercises/generics/generics1.rs
index 967287e..f93e64a 100644
--- a/exercises/generics/generics1.rs
+++ b/exercises/generics/generics1.rs
@@ -1,6 +1,8 @@
// 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() {
diff --git a/exercises/generics/generics2.rs b/exercises/generics/generics2.rs
index 0cb59ad..1501529 100644
--- a/exercises/generics/generics2.rs
+++ b/exercises/generics/generics2.rs
@@ -1,6 +1,8 @@
// 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 {
diff --git a/exercises/intro/README.md b/exercises/intro/README.md
new file mode 100644
index 0000000..d32e4a8
--- /dev/null
+++ b/exercises/intro/README.md
@@ -0,0 +1,8 @@
+# Intro
+
+Rust uses the `print!` and `println!` macros to print text to the console.
+
+## Further information
+
+- [Hello World](https://doc.rust-lang.org/rust-by-example/hello.html)
+- [Formatted print](https://doc.rust-lang.org/rust-by-example/hello/print.html)
diff --git a/exercises/intro/intro1.rs b/exercises/intro/intro1.rs
new file mode 100644
index 0000000..1c4582d
--- /dev/null
+++ b/exercises/intro/intro1.rs
@@ -0,0 +1,23 @@
+// intro1.rs
+// 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.
+// Execute the command `rustlings hint intro1` for a hint.
+
+// I AM NOT DONE
+
+fn main() {
+ println!("Hello and");
+ println!(r#" welcome to... "#);
+ println!(r#" _ _ _ "#);
+ println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
+ println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
+ println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
+ println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
+ println!(r#" |___/ "#);
+ println!();
+ println!("This exercise compiles successfully. The remaining exercises contain a compiler");
+ println!("or logic error. The central concept behind Rustlings is to fix these errors and");
+ println!("solve the exercises. Good luck!");
+}
diff --git a/exercises/intro/intro2.rs b/exercises/intro/intro2.rs
new file mode 100644
index 0000000..97a073f
--- /dev/null
+++ b/exercises/intro/intro2.rs
@@ -0,0 +1,9 @@
+// intro2.rs
+// Make the code print a greeting to the world.
+// Execute `rustlings hint intro2` for a hint.
+
+// I AM NOT DONE
+
+fn main() {
+ println!("Hello {}!");
+}
diff --git a/exercises/modules/README.md b/exercises/modules/README.md
index 6582b00..3dc8a48 100644
--- a/exercises/modules/README.md
+++ b/exercises/modules/README.md
@@ -4,4 +4,4 @@ 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)
+- [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
diff --git a/exercises/modules/modules1.rs b/exercises/modules/modules1.rs
index 812dfee..1a2bd0d 100644
--- a/exercises/modules/modules1.rs
+++ b/exercises/modules/modules1.rs
@@ -4,7 +4,13 @@
// I AM NOT DONE
mod sausage_factory {
+ // Don't let anybody outside of this module see this!
+ fn get_secret_recipe() -> String {
+ String::from("Ginger")
+ }
+
fn make_sausage() {
+ get_secret_recipe();
println!("sausage!");
}
}
diff --git a/exercises/modules/modules2.rs b/exercises/modules/modules2.rs
index fde439d..87f0c45 100644
--- a/exercises/modules/modules2.rs
+++ b/exercises/modules/modules2.rs
@@ -1,11 +1,15 @@
// modules2.rs
+// You can bring module paths into scopes and provide new names for them with the
+// 'use' and 'as' keywords. Fix these 'use' statements to make the code compile.
// 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;
+
+ // TODO: Fix these use statements
+ use self::fruits::PEAR as ???
+ use self::veggies::CUCUMBER as ???
mod fruits {
pub const PEAR: &'static str = "Pear";
diff --git a/exercises/modules/modules3.rs b/exercises/modules/modules3.rs
new file mode 100644
index 0000000..8eed77d
--- /dev/null
+++ b/exercises/modules/modules3.rs
@@ -0,0 +1,18 @@
+// modules3.rs
+// You can use the 'use' keyword to bring module paths from modules from anywhere
+// and especially from the Rust standard library into your scope.
+// Bring SystemTime and UNIX_EPOCH
+// from the std::time module. Bonus style points if you can do it with one line!
+// Make me compile! Execute `rustlings hint modules3` for hints :)
+
+// I AM NOT DONE
+
+// TODO: Complete this use statement
+use ???
+
+fn main() {
+ match SystemTime::now().duration_since(UNIX_EPOCH) {
+ Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
+ Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+ }
+}
diff --git a/exercises/move_semantics/move_semantics5.rs b/exercises/move_semantics/move_semantics5.rs
new file mode 100644
index 0000000..c4704f9
--- /dev/null
+++ b/exercises/move_semantics/move_semantics5.rs
@@ -0,0 +1,15 @@
+// move_semantics5.rs
+// Make me compile only by reordering the lines in `main()`, but without
+// adding, changing or removing any of them.
+// Execute `rustlings hint move_semantics5` for hints :)
+
+// I AM NOT DONE
+
+fn main() {
+ let mut x = 100;
+ let y = &mut x;
+ let z = &mut x;
+ *y += 100;
+ *z += 1000;
+ assert_eq!(x, 1200);
+}
diff --git a/exercises/option/README.md b/exercises/option/README.md
index a304bb4..89c0028 100644
--- a/exercises/option/README.md
+++ b/exercises/option/README.md
@@ -16,3 +16,5 @@ Option types are very common in Rust code, as they have a number of uses:
- [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)
+- [if let](https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html)
+- [while let](https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html)
diff --git a/exercises/option/option1.rs b/exercises/option/option1.rs
index 602ff1a..17cf4f6 100644
--- a/exercises/option/option1.rs
+++ b/exercises/option/option1.rs
@@ -3,7 +3,7 @@
// I AM NOT DONE
-// you can modify anything EXCEPT for this function's sig
+// you can modify anything EXCEPT for this function's signature
fn print_number(maybe_number: Option<u16>) {
println!("printing: {}", maybe_number.unwrap());
}
diff --git a/exercises/option/option3.rs b/exercises/option/option3.rs
new file mode 100644
index 0000000..045d2ac
--- /dev/null
+++ b/exercises/option/option3.rs
@@ -0,0 +1,19 @@
+// 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.
+}
diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs
index 2bb2c24..7bd3f58 100644
--- a/exercises/quiz1.rs
+++ b/exercises/quiz1.rs
@@ -2,15 +2,16 @@
// This is a quiz for the following sections:
// - Variables
// - Functions
+// - If
// 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!
+// the price of an order of apples given the quantity bought. No hints this time!
// I AM NOT DONE
// Put your function here!
-// fn ..... {
+// fn calculate_apple_price {
// Don't modify this function!
#[test]
diff --git a/exercises/standard_library_types/iterators1.rs b/exercises/standard_library_types/iterators1.rs
index 3fd519d..4606ad3 100644
--- a/exercises/standard_library_types/iterators1.rs
+++ b/exercises/standard_library_types/iterators1.rs
@@ -1,11 +1,11 @@
// 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
+// 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
diff --git a/exercises/standard_library_types/iterators5.rs b/exercises/standard_library_types/iterators5.rs
index 2d97bd4..93f3ae1 100644
--- a/exercises/standard_library_types/iterators5.rs
+++ b/exercises/standard_library_types/iterators5.rs
@@ -1,5 +1,4 @@
// 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
@@ -7,8 +6,7 @@
// 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.
+// Execute `rustlings hint iterators5` for hints.
//
// Make the code compile and the tests pass.
@@ -16,7 +14,7 @@
use std::collections::HashMap;
-#[derive(PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq)]
enum Progress {
None,
Some,
diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs
index 8d8b471..e84f2eb 100644
--- a/exercises/structs/structs3.rs
+++ b/exercises/structs/structs3.rs
@@ -16,13 +16,13 @@ struct Package {
impl Package {
fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
if weight_in_grams <= 0 {
- // Something goes here...
+ // panic statement goes here...
} else {
- return Package {
+ Package {
sender_country,
recipient_country,
weight_in_grams,
- };
+ }
}
}
@@ -31,7 +31,7 @@ impl Package {
}
fn get_fees(&self, cents_per_gram: i32) -> ??? {
- // Something goes here...
+ // Something goes here...
}
}
@@ -73,7 +73,7 @@ mod tests {
let sender_country = String::from("Spain");
let recipient_country = String::from("Spain");
- let cents_per_gram = ???;
+ let cents_per_gram = 3;
let package = Package::new(sender_country, recipient_country, 1500);
diff --git a/exercises/traits/traits1.rs b/exercises/traits/traits1.rs
index 2ef9e11..15e08f2 100644
--- a/exercises/traits/traits1.rs
+++ b/exercises/traits/traits1.rs
@@ -29,12 +29,12 @@ mod tests {
use super::*;
#[test]
- fn is_FooBar() {
+ fn is_foo_bar() {
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
}
#[test]
- fn is_BarBar() {
+ fn is_bar_bar() {
assert_eq!(
String::from("").append_bar().append_bar(),
String::from("BarBar")
diff --git a/exercises/variables/variables1.rs b/exercises/variables/variables1.rs
index 4a3af73..d1af831 100644
--- a/exercises/variables/variables1.rs
+++ b/exercises/variables/variables1.rs
@@ -1,10 +1,6 @@
// 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.
+// Make me compile!
+// Execute the command `rustlings hint variables1` if you want a hint :)
// I AM NOT DONE
diff --git a/exercises/variables/variables5.rs b/exercises/variables/variables5.rs
index da37ae9..175eebb 100644
--- a/exercises/variables/variables5.rs
+++ b/exercises/variables/variables5.rs
@@ -4,7 +4,7 @@
// I AM NOT DONE
fn main() {
- let number = "T-H-R-E-E";
+ 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);