Esimerkkiratkaisut

01-tuples

#![allow(unused)]
fn main() {
//! Use a tuple index operator to access the second element of
//! `numbers`.

#[test]
fn indexing_tuple() {
    let numbers = (1, 2, 3);
    // Create a variable holding the second number of the tuple.
    let second = numbers.1;

    assert_eq!(2, second, "This is not the second number in the tuple!")
}
}

02-tuples

//! Destructure the `cat` tuple so that the println will work.

fn main() {
    let cat = ("Furry McFurson", 3.5);
    let (name, age) = cat;

    println!("{} is {} years old.", name, age); // Don't change this line
}

03-tuples

//! Mutate the tuple so that the test passes

fn swap_tuple((x, y): (i32, i32)) -> (i32, i32) {
    (y, x)
}

fn main() {
    let mut tup = (2, 5);

    // TODO mutate the second element in `tup`
    tup.1 = 4;

    assert_eq!(swap_tuple(tup), (4, 2));
}

04-strings

//! Ok, here are a bunch of values-- some are `String`s, some are string slices:
//! `&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. There may be multiple
//! solutions.

fn string_slice(arg: &str) {
    println!("{}", arg);
}
fn string(arg: String) {
    println!("{}", arg);
}

fn main() {
    string_slice("blue");
    string("red".to_string());
    string(String::from("hi"));
    string("rust is fun!".to_owned());
    string("nice weather".into());
    string(format!("Interpolation {}", "Station"));
    string_slice(&String::from("abc")[0..1]);
    string_slice("  hello there ".trim());
    string("Happy Monday!".to_string().replace("Mon", "Tues"));
    string("mY sHiFt KeY iS sTiCkY".to_lowercase());
}

05-vectors

#![allow(unused)]
fn main() {
//! Step 1: fix `vec_loop` function's definition to allow using
//! `v.iter_mut()`.
//!
//! Step 2: complete the loop so that each number in the Vec is
//! multiplied by 2.

fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
    for elem in v.iter_mut() {
        // TODO: Fill this up so that each element in the Vec `v` is
        // multiplied by 2.  Hint: mutating the referent of `&mut i32`
        // requires a dereference.
        *elem *= 2;
    }

    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>>());
    }
}
}

06-slices

#![allow(unused)]
fn main() {
//! Your task is to take a nice slice into `a` so that the test passes.

#[test]
fn slice_out_of_array() {
    let a = [1, 2, 3, 4, 5];

    let nice_slice = &a[1..4];

    assert_eq!([2, 3, 4], nice_slice)
}
}

07-slices

#![allow(unused)]
fn main() {
//! 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! Use the `vec!` macro:
//! https://doc.rust-lang.org/std/macro.vec.html

fn array_and_vec() -> ([i32; 4], Vec<i32>) {
    let a = [10, 20, 30, 40];
    let v = vec![10, 20, 30, 40];

    (a, v)
}

#[test]
fn test_array_and_vec_similarity() {
    let (a, v) = array_and_vec();
    assert_eq!(a, v[..]);
}
}

08-slices

//! Note: if your editor complains about `try_into`, it only works on
//! edition 2021 which `otarustlings` supports, so don't mind the
//! error.

fn make_mult_table(num: i32) -> [String; 10] {
    // The _ here tells Rust that it needs to figure it out so that
    // you don't need to. The Vec is required as collect can return
    // any collection that implements the FromIterator trait.
    let vec: Vec<_> = (0..10)
        .into_iter()
        .map(|i| format!("{i} * {num} = {}", i as i32 * num))
        .collect();

    vec.try_into().expect("vector to have exactly 10 elements")
}

fn main() {
    let a = make_mult_table(3);

    // TODO create a reference to the correct element
    let nine = &a[3];

    println!("the array is {:#?}", a);
    assert_eq!(nine, "3 * 3 = 9");
}

09-borrowing

//! You can't change anything except adding or removing references `&`

fn main() {
    let data = "Rust is great!".to_string();

    get_char(&data);

    string_uppercase(data);
}

// TODO Should not take ownership
fn get_char(data: &String) -> char {
    data.chars().last().unwrap()
}

// TODO Should take ownership
fn string_uppercase(mut data: String) {
    data = data.to_uppercase();

    println!("{}", data);
}

10-borrowing

//! Your task is to fix the function `third`.  Hint: the issue is not
//! related to lifetimes.
//!
//! Note: The exercises use strings in array because they are not
//! cheap to copy (unlike integers for example).

// TODO fix "lifetime" errors
fn third(a: &[String]) -> (&[String], &str) {
    (a, &a[2])
}

// Don't edit the following code

fn eat(s: String) {
    println!("{}", s);
}

fn main() {
    let a = [
        "first".to_string(),
        "second".to_string(),
        "third".to_string(),
        "fourth".to_string(),
    ];

    let (b, third) = third(&a);

    println!("{}", third);

    eat(a
        .into_iter()
        .nth(1)
        .expect("a to contain at least two elements"));
}

11-structs

//! Your task is to mutate the point in main to pass the assertion

/// A struct is a statically sized collection of data with keys and values.
struct Point {
    x: i32,
    y: i32,
}

fn display_point(point: &Point) {
    println!("{}, {}", point.x, point.y);
}

fn main() {
    let mut point = Point {
        x: 3,
        y: -5,
    };

    // TODO mutate point's x-coordinate
    point.x = 6;

    display_point(&point);
    assert_eq!(point.x, 6);
}

12-strings

#![allow(unused)]
fn main() {
//! Your task is to capitalize the first letter/character in `string`. Search
//! the Rust standard library documentation for `str::chars`. Note that a String
//! has all the methods of str because of the `Deref` trait. Don't be afraid to
//! search more information online

fn capitalize_first(string: &mut String) {
    // First we take the first character, which can be multiple bytes, but one
    // UTF-8 character only (max 4 bytes). We do nothing and return if there is
    // no first character.

    // For example with "firm" the bytes are
    // string: [u8] = EF AC 81   72 6d
    //                ^^^^^^^^-fi r  m
    if let Some(first) = string.chars().next() {
        // the first character 'fi'
        // first: char = 01 fb 00 00

        // Next we create a string from the characters (yes there can be
        // multiple) which are now in uppercase.
        let first_uppercase = first.to_uppercase().collect::<String>();
        // first_uppercase: [u8] = 46   49
        //                         F    I
        let mut first_chars = first_uppercase.chars();

        if let Some(first_char) = first_chars.next() {
            // Next we take the first character and join it with the rest of
            // the characters after converting them to lowercase
            let first_capitalized = std::iter::once(first_char)
                .chain(first_chars.map(char::to_lowercase).flatten())
                .collect::<String>();

            // Finally we remove the first `len_utf8` bytes from the string and
            // prepend with the bytes from `first_uppercase`.
            // string.replace_range(..first.len_utf8(), &first_uppercase);
            // Behind the scenes the string is converted to vector and spliced with
            // the new data `first_uppercase`
            // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.splice

            string.replace_range(..first.len_utf8(), &first_capitalized);

            // and the string is
            // string: [u8] = 46 69 72 6d
            //                F  i  r  m
        }
    }
}

#[test]
fn letters() {
    let mut string = "testing".to_string();

    capitalize_first(&mut string);

    assert_eq!(string, "Testing");
}

#[test]
fn numbers() {
    let mut string = "1234".to_string();

    capitalize_first(&mut string);

    assert_eq!(string, "1234");
}

#[test]
fn special() {
    let mut string = "山".to_string();

    capitalize_first(&mut string);

    assert_eq!(string, "山");
}

#[test]
fn emoji() {
    let mut string = "❤".to_string();

    capitalize_first(&mut string);

    assert_eq!(string, "❤");
}

#[test]
fn sigma() {
    let mut string = "Σ".to_string();

    capitalize_first(&mut string);

    assert_eq!(string, "Σ");
}

// The hard one
#[test]
fn ligatures() {
    let mut string = "firm".to_string();

    capitalize_first(&mut string);

    assert_eq!(string, "Firm");
}
}

B1-vecdeque

//! This is a bonus exercise.
//! 
//! Your task is to find the right number to rotate the VecDeque by. You are
//! only allowed to change the argument to `rotate_right`

use std::collections::VecDeque;

fn make_uncontiguous_vecdeq() -> VecDeque<i32> {
    let mut vd: VecDeque<_> = (1..=5).chain(1..=5).collect();

    // TODO rotate the deque until both slices are equal
    vd.rotate_right(5);

    vd
}

fn main() {
    let vd = make_uncontiguous_vecdeq();

    let (head, tail) = vd.as_slices();

    assert_eq!(head, tail);
}

B2-traitobj-tuukka

//! This is a bonus exercise (hard)

use std::collections::HashMap;

fn make_vec() -> Vec<(&'static str, i32)> {
    vec![("a",1),("b",2),("c",3)]
}

fn make_hashmap() -> HashMap<&'static str, i32> {
    let mut hm = HashMap::new();
    hm.insert("d", 4);
    hm.insert("e", 5);
    hm.insert("f", 6);
    hm
}

// TODO fill in the blanks
fn print_dyn_iter(iter: &mut dyn Iterator<Item = (&str, i32)>) {
    for (key, value) in iter {
        println!("{key} - {value}")
    }
}

fn main() {
    let mut v = make_vec().into_iter();
    let mut hm = make_hashmap().into_iter();

    print_dyn_iter(&mut v);
    assert_eq!(v.next(), None);

    print_dyn_iter(&mut hm);
    assert_eq!(hm.next(), None);
}

B3-traitobj-tuukka

//! This is a bonus exercise (hard)
//! 
//! Your task is to make the main function not panic. You can only change code
//! inside main.
//! 
//! Part 1: swap the values of v and hm safely with something from
//! https://doc.rust-lang.org/std/mem/index.html
//! 
//! Part 2: fix the next problem ¯\_(°ペ)_/¯

use std::any::Any;
use std::collections::HashMap;

fn make_something() -> Box<dyn Any> {
    Box::new(vec![("a", 1), ("b", 2), ("c", 3)])
}

fn make_something_else() -> Box<dyn Any> {
    let mut hm = HashMap::new();
    hm.insert("d", 4);
    hm.insert("e", 5);
    hm.insert("f", 6);
    Box::new(hm)
}

fn check_type_vec(any: &mut dyn Any) {
    if let Some(vec) = any.downcast_ref::<Vec<(&str, i32)>>() {
        println!("is vector");
    } else {
        panic!("TypeError: Vec expected");
    }
}

fn check_type_hashmap(any: &mut dyn Any) {
    if let Some(hm) = any.downcast_ref::<HashMap<&str, i32>>() {
        println!("is hashmap");
    } else {
        panic!("TypeError: HashMap expected");
    }
}

// You can only edit code in the main function
fn main() {
    let mut v: Box<dyn Any> = make_something();
    let mut hm: Box<dyn Any> = make_something_else();

    std::mem::swap(&mut v, &mut hm);

    // Reborrow is needed to get a reference to the data inside the box
    check_type_hashmap(&mut *v);
    check_type_vec(&mut *hm);
}