Last active
May 17, 2023 02:33
-
-
Save totechite/6dce08cf75ab961e546f0578cdfbb27c to your computer and use it in GitHub Desktop.
My Rustlings answers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// move_semantics1.rs | |
// Make me compile! Scroll down for hints :) | |
pub 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> { | |
let mut vec = vec; | |
vec.push(22); | |
vec.push(44); | |
vec.push(66); | |
vec | |
} | |
// So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 11, | |
// right? The fix for this is going to be adding one keyword, and the addition is NOT on line 11 | |
// where the error is. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// move_semantics2.rs | |
// Make me compile without changing line 10! Scroll down for hints :) | |
pub fn main() { | |
let vec0 = Vec::new(); | |
let mut vec1 = fill_vec(vec0.clone()); | |
// 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 | |
} | |
// So `vec0` is being *moved* into the function `fill_vec` when we call it on | |
// line 7, which means it gets dropped at the end of `fill_vec`, which means we | |
// can't use `vec0` again on line 10 (or anywhere else in `main` after the | |
// `fill_vec` call for that matter). We could fix this in a few ways, try them | |
// all! | |
// 1. Make another, separate version of the data that's in `vec0` and pass that | |
// to `fill_vec` instead. | |
// 2. Make `fill_vec` borrow its argument instead of taking ownership of it, | |
// and then copy the data within the function in order to return an owned | |
// `Vec<i32>` | |
// 3. Make `fill_vec` *mutably* borrow its argument (which will need to be | |
// mutable), modify it directly, then not return anything. Then you can get rid | |
// of `vec1` entirely -- note that this will change what gets printed by the | |
// first `println!` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// move_semantics2.rs | |
// Make me compile without changing line 10! Scroll down for hints :) | |
pub 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.clone(); | |
vec.push(22); | |
vec.push(44); | |
vec.push(66); | |
vec | |
} | |
// So `vec0` is being *moved* into the function `fill_vec` when we call it on | |
// line 7, which means it gets dropped at the end of `fill_vec`, which means we | |
// can't use `vec0` again on line 10 (or anywhere else in `main` after the | |
// `fill_vec` call for that matter). We could fix this in a few ways, try them | |
// all! | |
// 1. Make another, separate version of the data that's in `vec0` and pass that | |
// to `fill_vec` instead. | |
// 2. Make `fill_vec` borrow its argument instead of taking ownership of it, | |
// and then copy the data within the function in order to return an owned | |
// `Vec<i32>` | |
// 3. Make `fill_vec` *mutably* borrow its argument (which will need to be | |
// mutable), modify it directly, then not return anything. Then you can get rid | |
// of `vec1` entirely -- note that this will change what gets printed by the | |
// first `println!` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// move_semantics2.rs | |
// Make me compile without changing line 10! Scroll down for hints :) | |
pub fn main() { | |
let mut vec0 = Vec::new(); | |
fill_vec(&mut vec0); | |
// Do not change the following line! | |
println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0); | |
} | |
fn fill_vec(vec: &mut Vec<i32>) { | |
let vec = vec; | |
vec.push(22); | |
vec.push(44); | |
vec.push(66); | |
} | |
// So `vec0` is being *moved* into the function `fill_vec` when we call it on | |
// line 7, which means it gets dropped at the end of `fill_vec`, which means we | |
// can't use `vec0` again on line 10 (or anywhere else in `main` after the | |
// `fill_vec` call for that matter). We could fix this in a few ways, try them | |
// all! | |
// 1. Make another, separate version of the data that's in `vec0` and pass that | |
// to `fill_vec` instead. | |
// 2. Make `fill_vec` borrow its argument instead of taking ownership of it, | |
// and then copy the data within the function in order to return an owned | |
// `Vec<i32>` | |
// 3. Make `fill_vec` *mutably* borrow its argument (which will need to be | |
// mutable), modify it directly, then not return anything. Then you can get rid | |
// of `vec1` entirely -- note that this will change what gets printed by the | |
// first `println!` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// move_semantics3.rs | |
// Make me compile without adding new lines-- just changing existing lines! | |
// (no lines with multiple semicolons necessary!) | |
// Scroll down for hints :) | |
pub 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(mut vec: Vec<i32>) -> Vec<i32> { | |
vec.push(22); | |
vec.push(44); | |
vec.push(66); | |
vec | |
} | |
// The difference between this one and the previous ones is that the first line | |
// of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can, | |
// instead of adding that line back, add `mut` in one place that will change | |
// an existing binding to be a mutable binding instead of an immutable one :) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// move_semantics4.rs | |
// Refactor this code so that instead of having `vec0` and creating the vector | |
// in `fn main`, we instead create it within `fn fill_vec` and transfer the | |
// freshly created vector from fill_vec to its caller. Scroll for hints! | |
pub fn main() { | |
let mut vec1 = fill_vec(); | |
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); | |
vec1.push(88); | |
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); | |
} | |
fn fill_vec() -> Vec<i32> { | |
[22, 44, 66].to_vec() | |
} | |
// Stop reading whenever you feel like you have enough direction :) Or try | |
// doing one step and then fixing the compiler errors that result! | |
// So the end goal is to: | |
// - get rid of the first line in main that creates the new vector | |
// - so then `vec0` doesn't exist, so we can't pass it to `fill_vec` | |
// - we don't want to pass anything to `fill_vec`, so its signature should | |
// reflect that it does not take any arguments | |
// - since we're not creating a new vec in `main` anymore, we need to create | |
// a new vec in `fill_vec`, similarly to the way we did in `main` |
Assuming others will arrive here from a search engine, as I did.
Here's my solutions for 5 and 6 (comments removed for brevity's sake); 6 was confusing at first but makes sense in retrospect:
move_semantics5.rs
fn main() {
let mut x = 100;
let y = &mut x;
*y += 100;
let z = &mut x;
*z += 1000;
assert_eq!(x, 1200);
}
move_semantics6.rs
fn main() {
let data = "Rust is great!".to_string();
get_char(&data);
string_uppercase(data);
}
fn get_char(data: &String) -> char {
data.chars().last().unwrap()
}
fn string_uppercase(mut data: String) {
data = data.to_uppercase();
println!("{}", data);
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You can comment line 15 in move_semantics2-3.rs