finish rustlings 🦀
This commit is contained in:
parent
4e473bac9d
commit
c29661905d
8 changed files with 562 additions and 19 deletions
|
@ -1,6 +1,6 @@
|
||||||
DON'T EDIT THIS FILE!
|
DON'T EDIT THIS FILE!
|
||||||
|
|
||||||
using_as
|
as_ref_mut
|
||||||
|
|
||||||
intro1
|
intro1
|
||||||
intro2
|
intro2
|
||||||
|
@ -90,4 +90,9 @@ macros3
|
||||||
macros4
|
macros4
|
||||||
clippy1
|
clippy1
|
||||||
clippy2
|
clippy2
|
||||||
clippy3
|
clippy3
|
||||||
|
using_as
|
||||||
|
from_into
|
||||||
|
from_str
|
||||||
|
try_from_into
|
||||||
|
as_ref_mut
|
|
@ -13,14 +13,14 @@
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
// TODO: Adjust the struct as described above.
|
// Adjust the struct as described above.
|
||||||
struct ReportCard<T> where T: Display {
|
struct ReportCard<T> where T: Display {
|
||||||
grade: T,
|
grade: T,
|
||||||
student_name: String,
|
student_name: String,
|
||||||
student_age: u8,
|
student_age: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Adjust the impl block as described above.
|
// Adjust the impl block as described above.
|
||||||
impl <T: Display>ReportCard<T> {
|
impl <T: Display>ReportCard<T> {
|
||||||
fn print(&self) -> String {
|
fn print(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
|
|
29
readme.md
Normal file
29
readme.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
# Rustlings
|
||||||
|
|
||||||
|
Rustlings is a project that contains small exercises to get you used to reading and writing Rust code!
|
||||||
|
|
||||||
|
This repo contains my solutions to the rustlings exercises, all 93/94 of them. ⭐
|
||||||
|
|
||||||
|
```bash
|
||||||
|
+----------------------------------------------------+
|
||||||
|
| You made it to the Fe-nish line! |
|
||||||
|
+-------------------------- ------------------------+
|
||||||
|
\/
|
||||||
|
▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒
|
||||||
|
▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒
|
||||||
|
▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒
|
||||||
|
░░▒▒▒▒░░▒▒ ▒▒ ▒▒ ▒▒ ▒▒░░▒▒▒▒
|
||||||
|
▓▓▓▓▓▓▓▓ ▓▓ ▓▓██ ▓▓ ▓▓██ ▓▓ ▓▓▓▓▓▓▓▓
|
||||||
|
▒▒▒▒ ▒▒ ████ ▒▒ ████ ▒▒░░ ▒▒▒▒
|
||||||
|
▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒
|
||||||
|
▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒
|
||||||
|
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
|
||||||
|
▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒
|
||||||
|
▒▒ ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒ ▒▒
|
||||||
|
▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒
|
||||||
|
▒▒ ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒
|
||||||
|
▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒
|
||||||
|
▒▒ ▒▒ ▒▒ ▒▒
|
||||||
|
|
||||||
|
```
|
|
@ -1,4 +1,59 @@
|
||||||
fn main() {
|
// AsRef and AsMut allow for cheap reference-to-reference conversions. Read more
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html and
|
||||||
// It will be automatically filled after you finish the exercise.
|
// https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
|
||||||
|
|
||||||
|
// Obtain the number of bytes (not characters) in the given argument.
|
||||||
|
fn byte_counter<T: AsRef<str>>(arg: T) -> usize {
|
||||||
|
arg.as_ref().as_bytes().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain the number of characters (not bytes) in the given argument.
|
||||||
|
fn char_counter<T: AsRef<str>>(arg: T) -> usize {
|
||||||
|
arg.as_ref().chars().count()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Squares a number using `as_mut()`.
|
||||||
|
fn num_sq<T: AsMut<u32>>(arg: &mut T) {
|
||||||
|
let arg = arg.as_mut();
|
||||||
|
*arg *= *arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// You can optionally experiment here.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mut_box() {
|
||||||
|
let mut num: Box<u32> = Box::new(3);
|
||||||
|
num_sq(&mut num);
|
||||||
|
assert_eq!(*num, 9);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,136 @@
|
||||||
fn main() {
|
// The `From` trait is used for value-to-value conversions. If `From` is
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// implemented, an implementation of `Into` is automatically provided.
|
||||||
// It will be automatically filled after you finish the exercise.
|
// You can read more about it in the documentation:
|
||||||
|
// https://doc.rust-lang.org/std/convert/trait.From.html
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Person {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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() -> Self {
|
||||||
|
Self {
|
||||||
|
name: String::from("John"),
|
||||||
|
age: 30,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Person {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let mut split = s.split(',');
|
||||||
|
let (Some(name), Some(age), None) = (split.next(), split.next(), split.next()) else {
|
||||||
|
// ^^^^ there should be no third element
|
||||||
|
return Self::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
if name.is_empty() {
|
||||||
|
return Self::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(age) = age.parse() else {
|
||||||
|
return Self::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
age,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Use the `from` function.
|
||||||
|
let p1 = Person::from("Mark,20");
|
||||||
|
println!("{p1:?}");
|
||||||
|
|
||||||
|
// Since `From` is implemented for Person, we are able to use `Into`.
|
||||||
|
let p2: Person = "Gerald,70".into();
|
||||||
|
println!("{p2:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default() {
|
||||||
|
let dp = Person::default();
|
||||||
|
assert_eq!(dp.name, "John");
|
||||||
|
assert_eq!(dp.age, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bad_convert() {
|
||||||
|
let p = Person::from("");
|
||||||
|
assert_eq!(p.name, "John");
|
||||||
|
assert_eq!(p.age, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_good_convert() {
|
||||||
|
let p = Person::from("Mark,20");
|
||||||
|
assert_eq!(p.name, "Mark");
|
||||||
|
assert_eq!(p.age, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bad_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,dog");
|
||||||
|
assert_eq!(p.name, "John");
|
||||||
|
assert_eq!(p.age, 30);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,117 @@
|
||||||
fn main() {
|
// This is similar to the previous `from_into` exercise. But this time, we'll
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// implement `FromStr` and return errors instead of falling back to a default
|
||||||
// It will be automatically filled after you finish the exercise.
|
// 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 in the documentation:
|
||||||
|
// https://doc.rust-lang.org/std/str/trait.FromStr.html
|
||||||
|
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct Person {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will use this error type for the `FromStr` implementation.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum ParsePersonError {
|
||||||
|
// Incorrect number of fields
|
||||||
|
BadLen,
|
||||||
|
// Empty name field
|
||||||
|
NoName,
|
||||||
|
// Wrapped error from parse::<u8>()
|
||||||
|
ParseInt(ParseIntError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Person {
|
||||||
|
type Err = ParsePersonError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut split = s.split(',');
|
||||||
|
let (Some(name), Some(age), None) = (split.next(), split.next(), split.next()) else {
|
||||||
|
// ^^^^ there should be no third element
|
||||||
|
return Err(ParsePersonError::BadLen);
|
||||||
|
};
|
||||||
|
|
||||||
|
if name.is_empty() {
|
||||||
|
return Err(ParsePersonError::NoName);
|
||||||
|
}
|
||||||
|
|
||||||
|
let age = age.parse().map_err(ParsePersonError::ParseInt)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
name: name.into(),
|
||||||
|
age,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let p = "Mark,20".parse::<Person>();
|
||||||
|
println!("{p:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use ParsePersonError::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_input() {
|
||||||
|
assert_eq!("".parse::<Person>(), Err(BadLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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!(matches!("John,".parse::<Person>(), Err(ParseInt(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_age() {
|
||||||
|
assert!(matches!("John,twenty".parse::<Person>(), Err(ParseInt(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_comma_and_age() {
|
||||||
|
assert_eq!("John".parse::<Person>(), Err(BadLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_name() {
|
||||||
|
assert_eq!(",1".parse::<Person>(), Err(NoName));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_name_and_age() {
|
||||||
|
assert!(matches!(",".parse::<Person>(), Err(NoName | ParseInt(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_name_and_invalid_age() {
|
||||||
|
assert!(matches!(
|
||||||
|
",one".parse::<Person>(),
|
||||||
|
Err(NoName | ParseInt(_)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trailing_comma() {
|
||||||
|
assert_eq!("John,32,".parse::<Person>(), Err(BadLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trailing_comma_and_some_string() {
|
||||||
|
assert_eq!("John,32,man".parse::<Person>(), Err(BadLen));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,193 @@
|
||||||
fn main() {
|
// `TryFrom` is a simple and safe type conversion that may fail in a controlled
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// way under some circumstances. Basically, this is the same as `From`. The main
|
||||||
// It will be automatically filled after you finish the exercise.
|
// difference is that this should return a `Result` type instead of the target
|
||||||
|
// type itself. You can read more about it in the documentation:
|
||||||
|
// https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
||||||
|
|
||||||
|
#![allow(clippy::useless_vec)]
|
||||||
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct Color {
|
||||||
|
red: u8,
|
||||||
|
green: u8,
|
||||||
|
blue: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will use this error type for the `TryFrom` conversions.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum IntoColorError {
|
||||||
|
// Incorrect length of slice
|
||||||
|
BadLen,
|
||||||
|
// Integer conversion error
|
||||||
|
IntConversion,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<(i16, i16, i16)> for Color {
|
||||||
|
type Error = IntoColorError;
|
||||||
|
|
||||||
|
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
|
||||||
|
let (Ok(red), Ok(green), Ok(blue)) = (
|
||||||
|
u8::try_from(tuple.0),
|
||||||
|
u8::try_from(tuple.1),
|
||||||
|
u8::try_from(tuple.2),
|
||||||
|
) else {
|
||||||
|
return Err(IntoColorError::IntConversion);
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self { red, green, blue })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<[i16; 3]> for Color {
|
||||||
|
type Error = IntoColorError;
|
||||||
|
|
||||||
|
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
|
||||||
|
// Reuse the implementation for a tuple.
|
||||||
|
Self::try_from((arr[0], arr[1], arr[2]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&[i16]> for Color {
|
||||||
|
type Error = IntoColorError;
|
||||||
|
|
||||||
|
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
|
||||||
|
// Check the length.
|
||||||
|
if slice.len() != 3 {
|
||||||
|
return Err(IntoColorError::BadLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reuse the implementation for a tuple.
|
||||||
|
Self::try_from((slice[0], slice[1], slice[2]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Using the `try_from` function.
|
||||||
|
let c1 = Color::try_from((183, 65, 14));
|
||||||
|
println!("{c1:?}");
|
||||||
|
|
||||||
|
// Since `TryFrom` is implemented for `Color`, we can use `TryInto`.
|
||||||
|
let c2: Result<Color, _> = [183, 65, 14].try_into();
|
||||||
|
println!("{c2:?}");
|
||||||
|
|
||||||
|
let v = vec![183, 65, 14];
|
||||||
|
// With slice we should use the `try_from` function
|
||||||
|
let c3 = Color::try_from(&v[..]);
|
||||||
|
println!("{c3:?}");
|
||||||
|
// or put the slice within round brackets and use `try_into`.
|
||||||
|
let c4: Result<Color, _> = (&v[..]).try_into();
|
||||||
|
println!("{c4:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use IntoColorError::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_out_of_range_positive() {
|
||||||
|
assert_eq!(Color::try_from((256, 1000, 10000)), Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_out_of_range_negative() {
|
||||||
|
assert_eq!(Color::try_from((-1, -10, -256)), Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_sum() {
|
||||||
|
assert_eq!(Color::try_from((-1, 255, 255)), Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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_eq!(c, Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_array_out_of_range_negative() {
|
||||||
|
let c: Result<Color, _> = [-10, -256, -1].try_into();
|
||||||
|
assert_eq!(c, Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_array_sum() {
|
||||||
|
let c: Result<Color, _> = [-1, 255, 255].try_into();
|
||||||
|
assert_eq!(c, Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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_eq!(Color::try_from(&arr[..]), Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slice_out_of_range_negative() {
|
||||||
|
let arr = [-256, -1, -10];
|
||||||
|
assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slice_sum() {
|
||||||
|
let arr = [-1, 255, 255];
|
||||||
|
assert_eq!(Color::try_from(&arr[..]), Err(IntConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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_eq!(Color::try_from(&v[..]), Err(BadLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slice_insufficient_length() {
|
||||||
|
let v = vec![0, 0];
|
||||||
|
assert_eq!(Color::try_from(&v[..]), Err(BadLen));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,24 @@
|
||||||
fn main() {
|
// Type casting in Rust is done via the usage of the `as` operator.
|
||||||
// DON'T EDIT THIS SOLUTION FILE!
|
// Note that the `as` operator is not only used when type casting. It also helps
|
||||||
// It will be automatically filled after you finish the exercise.
|
// with renaming imports.
|
||||||
|
|
||||||
|
fn average(values: &[f64]) -> f64 {
|
||||||
|
let total = values.iter().sum::<f64>();
|
||||||
|
total / values.len() as f64
|
||||||
|
// ^^^^^^
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue