Last active
February 19, 2022 05:02
-
-
Save spdrman/c3b716421ab83bea50447a20e46dd8ce to your computer and use it in GitHub Desktop.
Rust Ownership / Borrowing / Error handling
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
// Transfering ownership of a var to a function, and then back to main() | |
fn main() { | |
let mut array_main: [Vec<u8>; 3] = [vec![1], vec![2, 4], vec![]]; | |
print(&mut array_main); //pass as mutable reference to array_main | |
println!("{:?}", array_main); | |
} | |
fn print(array: &mut [Vec<u8>; 3]) -> &[Vec<u8>; 3] { | |
for e in array.iter() { | |
println!("{:?}", e) | |
} | |
*array = [vec![2], vec![3, 5], vec![]]; // take ownership / borrow & change array_main | |
array // pass ownership back to main() | |
} | |
// STRINGS in RUST | |
// https://stackoverflow.com/questions/24158114/what-are-the-differences-between-rusts-string-and-str | |
// https://medium.com/@alisomay/strings-in-rust-28c08a2d3130 | |
// Strings can be modified and enlarged (read+write) -- Str / &Str are like fixed sized arrays (read-only) | |
// ERROR handling in RUST | |
// https://stackoverflow.com/questions/57794849/result-getting-unexpected-type-argument | |
// https://nick.groenen.me/posts/rust-error-handling/ | |
// https://dmerej.info/blog/post/killing-unwrap/ | |
/* | |
thiserror is a great helper if you want to build meaningful error types | |
- I would highly recommend it to write errors you want to handle. | |
anyhow is useful if you don't particularly care what kind of error it is | |
- very handy when you simply want to handle "any" error. | |
For a binary, I would generally start any API with anyhow, until you need to differentiate between errors | |
- then create your new error type from thiserror::Error, swap our Result<T, anyhow::Error> with your error, | |
and handle it appropriately upstream. | |
For a library, I would create a general Error type for my whole library and return Result<T, crate::Error> everywhere; | |
adding in #[from] T conversions whenever I need to bubble up a new error type. | |
Then specialize as needed, ie an IoError. | |
*/ | |
// Use Result<T, Box<dyn Error>> when not sure what error type to use | |
pub fn from_config(filename: &str) -> io::Result<Self> { | |
let file = File::open(filename)?; | |
// This has no error possibility -- returns a Result<T, E> where E is module specific | |
let args: Vec<String> = read_config(file); | |
// Pull out all errors and convert to type std::io::ErrorKind::NotFound | |
let params: Option<(String, String, String, String)> = args.drain(0..4).tuples().next(); | |
params.ok_or(std::io::Error::new(std::io::ErrorKind::NotFound, "Could not read values into struct")).map(|(a, b, c, d)| BasicExample::new(a,b,c,d)) | |
} | |
/// #[derive(Debug, Deserialize, Eq, PartialEq)] | |
/// struct Row { | |
/// city: String, | |
/// country: String, | |
/// #[serde(rename = "popcount")] | |
/// population: u64, | |
/// } | |
/// | |
/// # fn main() { example().unwrap(); } | |
/// fn example() -> Result<(), Box<dyn Error>> { | |
/// let data = "\ | |
/// city,country,popcount | |
/// Boston,United States,4628910 | |
/// "; | |
/// let rdr = Reader::from_reader(data.as_bytes()); | |
/// let mut iter = rdr.into_deserialize(); | |
/// | |
/// if let Some(result) = iter.next() { | |
/// let record: Row = result?; | |
/// assert_eq!(record, Row { | |
/// city: "Boston".to_string(), | |
/// country: "United States".to_string(), | |
/// population: 4628910, | |
/// }); | |
/// Ok(()) | |
/// } else { | |
/// Err(From::from("expected at least one record but got none")) | |
/// } | |
/// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment