From 8c51b17ef7176de9ca7afdb5f1d51dd3905ba555 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 19 May 2019 22:09:30 -0700 Subject: rust Option/Result map() tricks --- software/rust.page | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'software/rust.page') diff --git a/software/rust.page b/software/rust.page index df99de4..4e8aa44 100644 --- a/software/rust.page +++ b/software/rust.page @@ -3,9 +3,10 @@ Rust ## Resources -- [http://xion.io/post/code/rust-iter-patterns.html]() -- [https://deterministic.space/rust-cli-tips.html]() -- [https://manishearth.github.io/blog/2018/01/10/whats-tokio-and-async-io-all-about/]() +- +- +- +- Optimization: use `RUSTFLAGS="-C target-cpu=native"` to take advantage of CPU special features. @@ -22,3 +23,40 @@ Run tests with stdout output: To run tests with logging enabled (eg, with `env_logger`), make sure you add `env_logger::init()` to the test function itself. + + +## map() and Result Ergonomics + +`.collect()` has some magical features! In addition to turning an iterator of +`Item` into `Vec`, it will turn an iterator of `Result` into +`Result>`. This makes it really useful for the end of functions. + +This is particularly useful for resolving some categories of "error handling in +map closures": you can use `?` in the map closure as long as you wrap the happy +path with `Ok()` and call collect on the outside. Eg: + + let list: Vec = junk + .iter() + .map(|thing| Ok(Item { + a: thing.a, + b: fixup(thing.widget)?, + })) + .collect::Result>()?; + +What about when `map` over an `Option`? Eg: + + let toy = Shiny { + a: 123, + b: component.map(|v| paint(v).expect("paint to succeed"), + }; + +Should use match in this case: + + let toy = Shiny { + a: 123, + b: match component { + None => None, + Some(v) => Some(paint(v)?), + }, + }; + -- cgit v1.2.3 From 1c5f02be0189e905965395c2083ee5dab5fb71ff Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 18 May 2020 16:08:16 -0700 Subject: rust learning notes --- software/rust.page | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'software/rust.page') diff --git a/software/rust.page b/software/rust.page index 4e8aa44..dc900c8 100644 --- a/software/rust.page +++ b/software/rust.page @@ -60,3 +60,76 @@ Should use match in this case: }, }; +## 2020-05-17 Reading + +While working on fatcat-cli tool, checked the The Rust Programming Language +book to read about trait objects and the `dyn` keyword, which I had ignored +previously. + +They seem like they could be used in a few places in fatcat-server rust code. +We don't particularly care about per-function-call performance there, and most +entities are already allocated on the heap. + +Other small syntax and thing learned: + +Can copy a struct while only updating specific fields with ".." syntax. Might +use this in fatcat-cli for update mutation. + +This is the cleanest example of using ErrorKind that I have seen: + + let f = match f { + Ok(file) => file, + Err(error) => match error.kind() { + ErrorKind::NotFound => match File::create("hello.txt") { + Ok(fc) => fc, + Err(e) => panic!("Problem creating the file: {:?}", e), + }, + other_error => { + panic!("Problem opening the file: {:?}", other_error) + } + }, + }; + +I didn't realize that test code may get compiled into non-test binaries unless +annotated with `#[cfg(test)]`. You are supposed to create a sub-module within +each `src/` file with unittests, like: + + #[cfg(test)] + mod tests { + use super::*; + + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } + } +This doesn't apply to `tests/` directory, which is for integration tests. + +The common pattern for binary crates (vs. library crates) is to have `main.rs` +and `lib.rs`, with any code that needs to be tested in `lib.rs` (aka, all the +actual logic). + +I think I knew `eprintln!()` (for stderr) vs. `println!()` (for stdout), but +good to remember. + +There is a description of how to avoid memory leaks with reference counting +using "weak" `Rc` references. Probably worth reading the [entire chapter on smart pointers](https://doc.rust-lang.org/book/ch15-06-reference-cycles.html#preventing-reference-cycles-turning-an-rct-into-a-weakt) +(including Box, Rc, RefCell) again. + +For the `Sized` trait, and `Sized` trait alone, can specify an ambiguous trait +constraint with `?` to indicate "may or may not be Sized", which doesn't really +mean anything but does explicitly allow generic functions over non-sized traits +like: + + fn my_generic_func(t: &T) { + // --snip-- + } + +A trait can depend on another trait. For example, a PrettyPrint trait could +rely on Display (and impl functions could call functions from Display). This is +done on the trait definition line. Such a trait is called a "supertrait". + +Implementing Deref on a wrapper type allows transparent access to all the trait +methods on the interior object. + +Also, a new longer post on error handling: -- cgit v1.2.3