about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-02-13 06:44:15 +0100
committerGitHub <noreply@github.com>2022-02-13 06:44:15 +0100
commit783b56ba68c5737d9593c6e9bb964b44b6889ddc (patch)
tree6ee858a418d57f41fd4f6f3629dd04abcd69b075
parentaff74a16971237f45182843388ac662c1822f960 (diff)
parentf6f93fd7ba348a4e0e2e9ca7af597d117d6337a1 (diff)
Rollup merge of #93851 - cyqsimon:option-examples, r=scottmcm
More practical examples for `Option::and_then` & `Result::and_then`

To be blatantly honest, I think the current example given for `Option::and_then` is objectively terrible. (No offence to whoever wrote them initially.)

```rust
fn sq(x: u32) -> Option<u32> { Some(x * x) }
fn nope(_: u32) -> Option<u32> { None }

assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
assert_eq!(Some(2).and_then(sq).and_then(nope), None);
assert_eq!(Some(2).and_then(nope).and_then(sq), None);
assert_eq!(None.and_then(sq).and_then(sq), None);
```

Current example:
 - does not demonstrate that `and_then` converts `Option<T>` to `Option<U>`
 - is far removed from any realistic code
 - generally just causes more confusion than it helps

So I replaced them with two blocks:
 - the first one shows basic usage (including the type conversion)
 - the second one shows an example of typical usage

Same thing with `Result::and_then`.

Hopefully this helps with clarity.
-rw-r--r--library/core/src/option.rs24
-rw-r--r--library/core/src/result.rs26
2 files changed, 37 insertions, 13 deletions
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index ec04692d3e0..508837f63c3 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1207,13 +1207,25 @@ impl<T> Option<T> {
     /// # Examples
     ///
     /// ```
-    /// fn sq(x: u32) -> Option<u32> { Some(x * x) }
-    /// fn nope(_: u32) -> Option<u32> { None }
+    /// fn sq_then_to_string(x: u32) -> Option<String> {
+    ///     x.checked_mul(x).map(|sq| sq.to_string())
+    /// }
+    ///
+    /// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
+    /// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
+    /// assert_eq!(None.and_then(sq_then_to_string), None);
+    /// ```
+    ///
+    /// Often used to chain fallible operations that may return [`None`].
+    ///
+    /// ```
+    /// let arr_2d = [["A0", "A1"], ["B0", "B1"]];
+    ///
+    /// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
+    /// assert_eq!(item_0_1, Some(&"A1"));
     ///
-    /// assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
-    /// assert_eq!(Some(2).and_then(sq).and_then(nope), None);
-    /// assert_eq!(Some(2).and_then(nope).and_then(sq), None);
-    /// assert_eq!(None.and_then(sq).and_then(sq), None);
+    /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
+    /// assert_eq!(item_2_0, None);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 05b4fa035b1..801e3a0b3a4 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1281,16 +1281,28 @@ impl<T, E> Result<T, E> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
+    /// ```
+    /// fn sq_then_to_string(x: u32) -> Result<String, &'static str> {
+    ///     x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")
+    /// }
     ///
+    /// assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));
+    /// assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));
+    /// assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
     /// ```
-    /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
-    /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
     ///
-    /// assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16));
-    /// assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4));
-    /// assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2));
-    /// assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));
+    /// Often used to chain fallible operations that may return [`Err`].
+    ///
+    /// ```
+    /// use std::{io::ErrorKind, path::Path};
+    ///
+    /// // Note: on Windows "/" maps to "C:\"
+    /// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());
+    /// assert!(root_modified_time.is_ok());
+    ///
+    /// let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());
+    /// assert!(should_fail.is_err());
+    /// assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]