From aa3e08fcfbab65879feb3fbee7f5c24dbe130f48 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Thu, 20 Mar 2025 20:04:40 -0500 Subject: [PATCH] fixing ownership issues done, may have to come back --- ch4/fixing_ownership_issues/Cargo.lock | 7 ++ ch4/fixing_ownership_issues/Cargo.toml | 6 ++ ch4/fixing_ownership_issues/src/main.rs | 113 ++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 ch4/fixing_ownership_issues/Cargo.lock create mode 100644 ch4/fixing_ownership_issues/Cargo.toml create mode 100644 ch4/fixing_ownership_issues/src/main.rs diff --git a/ch4/fixing_ownership_issues/Cargo.lock b/ch4/fixing_ownership_issues/Cargo.lock new file mode 100644 index 0000000..3377aa2 --- /dev/null +++ b/ch4/fixing_ownership_issues/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "fixing_ownership_issues" +version = "0.1.0" diff --git a/ch4/fixing_ownership_issues/Cargo.toml b/ch4/fixing_ownership_issues/Cargo.toml new file mode 100644 index 0000000..5be6719 --- /dev/null +++ b/ch4/fixing_ownership_issues/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "fixing_ownership_issues" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/ch4/fixing_ownership_issues/src/main.rs b/ch4/fixing_ownership_issues/src/main.rs new file mode 100644 index 0000000..6a910aa --- /dev/null +++ b/ch4/fixing_ownership_issues/src/main.rs @@ -0,0 +1,113 @@ +// This section covers some common ownership errors. +// I'll probably have to come back to this section. I'm not enjoying +// this part of Rust so learning this is not my favorite. + +use std::rc::Rc; + +fn main() { + // ------------------------------------------------------------------------ + // fixing an unsafe program: not enough permissions + + let name = vec![String::from("Ferris!")]; + let first = &name[0]; + stringify_name_with_title(&name); + println!("{}", first); + + // ------------------------------------------------------------------------ + // fixing an unsafe program: copying vs. moving out of a collection + + let v: Vec = vec![0, 1, 2]; + let n_ref: &i32 = &v[0]; + let n: i32 = *n_ref; + + // If a value does not own head data, then it can be copied without a move + // Unlike what's happening below + // i32 doesn't own head data, so it can be copied without a move + // String does own heap data, so it can't be copied without a move + // &String doesn't own heap data, so it can be copied without a move + // Solution 1: Avoid taking ownership with immutable reference + let vs: Vec = vec![String::from("Hello world")]; + let s_ref: &String = &vs[0]; + // let s: String = *s_ref; + println!("{s_ref}"); + // Solution 2: Clone the data if want ownership + // Solution 3: Use Vec::remove to move string out of the vector + + // ------------------------------------------------------------------------ + // fixing an safe program: mutating different tuple fields + + let mut name = (String::from("Ferris"), String::from("Rustacean")); + let first = &name.0; + name.1.push_str(", Esq."); + println!("{first} {}", name.1); +} + +// fixing an unsafe program: returing a reference to the stack +// fn return_a_string() -> &String { +// let s = String::from("Hello World"); +// &s +// fails because this function will get allocated but s is owned by this function. +// } + +fn return_a_string_diff_owner() -> String { + let s = String::from("Hello world"); + s +} + +// static means it lives forever +fn return_a_string_static() -> &'static str { + "Hello world" +} + +// rc is a reference-counted pointer. More in ch14 +// only clones a pointer to s and not the data itself +fn return_a_string_rc() -> Rc { + let s = Rc::new(String::from("Hello world")); + Rc::clone(&s) +} + +// caller provides a slot with a mutable reference +fn return_a_string_slot(output: &mut String) { + output.replace_range(.., "Hello world"); +} + +// fixing an unsafe program: not enough permissions +// Replace "&Vec" with "$mut Vec". THIS IS NOT A GOOD SOLUTION! +// Functions shouldn't mutate their inputs if the caller would not expect it. +// Basically just don't use mut in functions. Make a copy of the variable instead +// if mutating it. +fn stringify_name_with_title(name: &Vec) -> String { + let mut name_clone = name.clone(); + name_clone.push(String::from("Esq.")); + let full = name_clone.join(" "); + full +} + +fn stringify_name_with_title_final(name: &Vec) -> String { + let mut full = name.join(" "); + full.push_str(" Esq."); + full +} + +// fixing an unsafe program: aliasing and mutating a data structure +// This function fails +// fn add_big_strings(dst: &mut Vec, src: &[String]) { +// let largest: &String = dst.iter().max_by_key(|s| s.len()).unwrap(); +// for s in src { +// if s.len() > largest.len() { +// dst.push(s.clone()); +// } +// } +// } + +// The fix for above since we only need the length +// Shortens the lifetime of borrows on dst to not overlap with +// mutation to dst. +fn add_big_strings(dst: &mut Vec, src: &[String]) { + let largest_len: usize = dst.iter().max_by_key(|s| s.len()).unwrap().len(); + for s in src { + if s.len() > largest_len { + dst.push(s.clone()); + } + } +}