Skip to content

Commit a08f25a

Browse files
committed
Auto merge of #86211 - tlyu:option-result-overviews, r=joshtriplett
create method overview docs for core::option and core::result The `Option` and `Result` types have large lists of methods. They each could use an overview page of methods grouped by category. These proposed overviews include "truth tables" for the underappreciated boolean operators/combinators of these types. The methods are already somewhat categorized in the source, but some logical groupings are broken up by the necessities of putting related methods in different `impl` blocks, for example. This is based on #86209, but those are small changes and unlikely to conflict.
2 parents 2155386 + 2b4a6aa commit a08f25a

File tree

2 files changed

+583
-5
lines changed

2 files changed

+583
-5
lines changed

library/core/src/option.rs

+339-5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
//! no "null" references. Instead, Rust has *optional* pointers, like
5050
//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
5151
//!
52+
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
53+
//!
5254
//! The following example uses [`Option`] to create an optional box of
5355
//! [`i32`]. Notice that in order to use the inner [`i32`] value, the
5456
//! `check_optional` function first needs to use pattern matching to
@@ -83,13 +85,350 @@
8385
//! * [`ptr::NonNull<U>`]
8486
//! * `#[repr(transparent)]` struct around one of the types in this list.
8587
//!
88+
//! [`Box<U>`]: ../../std/boxed/struct.Box.html
89+
//! [`num::NonZero*`]: crate::num
90+
//! [`ptr::NonNull<U>`]: crate::ptr::NonNull
91+
//!
8692
//! This is called the "null pointer optimization" or NPO.
8793
//!
8894
//! It is further guaranteed that, for the cases above, one can
8995
//! [`mem::transmute`] from all valid values of `T` to `Option<T>` and
9096
//! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T`
9197
//! is undefined behaviour).
9298
//!
99+
//! # Method overview
100+
//!
101+
//! In addition to working with pattern matching, [`Option`] provides a wide
102+
//! variety of different methods.
103+
//!
104+
//! ## Querying the variant
105+
//!
106+
//! The [`is_some`] and [`is_none`] methods return [`true`] if the [`Option`]
107+
//! is [`Some`] or [`None`], respectively.
108+
//!
109+
//! [`is_none`]: Option::is_none
110+
//! [`is_some`]: Option::is_some
111+
//!
112+
//! ## Adapters for working with references
113+
//!
114+
//! * [`as_ref`] converts from `&Option<T>` to `Option<&T>`
115+
//! * [`as_mut`] converts from `&mut Option<T>` to `Option<&mut T>`
116+
//! * [`as_deref`] converts from `&Option<T>` to `Option<&T::Target>`
117+
//! * [`as_deref_mut`] converts from `&mut Option<T>` to
118+
//! `Option<&mut T::Target>`
119+
//! * [`as_pin_ref`] converts from [`Pin`]`<&Option<T>>` to
120+
//! `Option<`[`Pin`]`<&T>>`
121+
//! * [`as_pin_mut`] converts from [`Pin`]`<&mut Option<T>>` to
122+
//! `Option<`[`Pin`]`<&mut T>>`
123+
//!
124+
//! [`as_deref`]: Option::as_deref
125+
//! [`as_deref_mut`]: Option::as_deref_mut
126+
//! [`as_mut`]: Option::as_mut
127+
//! [`as_pin_mut`]: Option::as_pin_mut
128+
//! [`as_pin_ref`]: Option::as_pin_ref
129+
//! [`as_ref`]: Option::as_ref
130+
//!
131+
//! ## Extracting the contained value
132+
//!
133+
//! These methods extract the contained value in an [`Option<T>`] when it
134+
//! is the [`Some`] variant. If the [`Option`] is [`None`]:
135+
//!
136+
//! * [`expect`] panics with a provided custom message
137+
//! * [`unwrap`] panics with a generic message
138+
//! * [`unwrap_or`] returns the provided default value
139+
//! * [`unwrap_or_default`] returns the default value of the type `T`
140+
//! (which must implement the [`Default`] trait)
141+
//! * [`unwrap_or_else`] returns the result of evaluating the provided
142+
//! function
143+
//!
144+
//! [`expect`]: Option::expect
145+
//! [`unwrap`]: Option::unwrap
146+
//! [`unwrap_or`]: Option::unwrap_or
147+
//! [`unwrap_or_default`]: Option::unwrap_or_default
148+
//! [`unwrap_or_else`]: Option::unwrap_or_else
149+
//!
150+
//! ## Transforming contained values
151+
//!
152+
//! These methods transform [`Option`] to [`Result`]:
153+
//!
154+
//! * [`ok_or`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to
155+
//! [`Err(err)`] using the provided default `err` value
156+
//! * [`ok_or_else`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to
157+
//! a value of [`Err`] using the provided function
158+
//! * [`transpose`] transposes an [`Option`] of a [`Result`] into a
159+
//! [`Result`] of an [`Option`]
160+
//!
161+
//! [`Err(err)`]: Err
162+
//! [`Ok(v)`]: Ok
163+
//! [`Some(v)`]: Some
164+
//! [`ok_or`]: Option::ok_or
165+
//! [`ok_or_else`]: Option::ok_or_else
166+
//! [`transpose`]: Option::transpose
167+
//!
168+
//! These methods transform the [`Some`] variant:
169+
//!
170+
//! * [`filter`] calls the provided predicate function on the contained
171+
//! value `t` if the [`Option`] is [`Some(t)`], and returns [`Some(t)`]
172+
//! if the function returns `true`; otherwise, returns [`None`]
173+
//! * [`flatten`] removes one level of nesting from an
174+
//! [`Option<Option<T>>`]
175+
//! * [`map`] transforms [`Option<T>`] to [`Option<U>`] by applying the
176+
//! provided function to the contained value of [`Some`] and leaving
177+
//! [`None`] values unchanged
178+
//!
179+
//! [`Some(t)`]: Some
180+
//! [`filter`]: Option::filter
181+
//! [`flatten`]: Option::flatten
182+
//! [`map`]: Option::map
183+
//!
184+
//! These methods transform [`Option<T>`] to a value of a possibly
185+
//! different type `U`:
186+
//!
187+
//! * [`map_or`] applies the provided function to the contained value of
188+
//! [`Some`], or returns the provided default value if the [`Option`] is
189+
//! [`None`]
190+
//! * [`map_or_else`] applies the provided function to the contained value
191+
//! of [`Some`], or returns the result of evaluating the provided
192+
//! fallback function if the [`Option`] is [`None`]
193+
//!
194+
//! [`map_or`]: Option::map_or
195+
//! [`map_or_else`]: Option::map_or_else
196+
//!
197+
//! These methods combine the [`Some`] variants of two [`Option`] values:
198+
//!
199+
//! * [`zip`] returns [`Some((s, o))`] if `self` is [`Some(s)`] and the
200+
//! provided [`Option`] value is [`Some(o)`]; otherwise, returns [`None`]
201+
//! * [`zip_with`] calls the provided function `f` and returns
202+
//! [`Some(f(s, o))`] if `self` is [`Some(s)`] and the provided
203+
//! [`Option`] value is [`Some(o)`]; otherwise, returns [`None`]
204+
//!
205+
//! [`Some(f(s, o))`]: Some
206+
//! [`Some(o)`]: Some
207+
//! [`Some(s)`]: Some
208+
//! [`Some((s, o))`]: Some
209+
//! [`zip`]: Option::zip
210+
//! [`zip_with`]: Option::zip_with
211+
//!
212+
//! ## Boolean operators
213+
//!
214+
//! These methods treat the [`Option`] as a boolean value, where [`Some`]
215+
//! acts like [`true`] and [`None`] acts like [`false`]. There are two
216+
//! categories of these methods: ones that take an [`Option`] as input, and
217+
//! ones that take a function as input (to be lazily evaluated).
218+
//!
219+
//! The [`and`], [`or`], and [`xor`] methods take another [`Option`] as
220+
//! input, and produce an [`Option`] as output. Only the [`and`] method can
221+
//! produce an [`Option<U>`] value having a different inner type `U` than
222+
//! [`Option<T>`].
223+
//!
224+
//! | method | self | input | output |
225+
//! |---------|-----------|-----------|-----------|
226+
//! | [`and`] | `None` | (ignored) | `None` |
227+
//! | [`and`] | `Some(x)` | `None` | `None` |
228+
//! | [`and`] | `Some(x)` | `Some(y)` | `Some(y)` |
229+
//! | [`or`] | `None` | `None` | `None` |
230+
//! | [`or`] | `None` | `Some(y)` | `Some(y)` |
231+
//! | [`or`] | `Some(x)` | (ignored) | `Some(x)` |
232+
//! | [`xor`] | `None` | `None` | `None` |
233+
//! | [`xor`] | `None` | `Some(y)` | `Some(y)` |
234+
//! | [`xor`] | `Some(x)` | `None` | `Some(x)` |
235+
//! | [`xor`] | `Some(x)` | `Some(y)` | `None` |
236+
//!
237+
//! [`and`]: Option::and
238+
//! [`or`]: Option::or
239+
//! [`xor`]: Option::xor
240+
//!
241+
//! The [`and_then`] and [`or_else`] methods take a function as input, and
242+
//! only evaluate the function when they need to produce a new value. Only
243+
//! the [`and_then`] method can produce an [`Option<U>`] value having a
244+
//! different inner type `U` than [`Option<T>`].
245+
//!
246+
//! | method | self | function input | function result | output |
247+
//! |--------------|-----------|----------------|-----------------|-----------|
248+
//! | [`and_then`] | `None` | (not provided) | (not evaluated) | `None` |
249+
//! | [`and_then`] | `Some(x)` | `x` | `None` | `None` |
250+
//! | [`and_then`] | `Some(x)` | `x` | `Some(y)` | `Some(y)` |
251+
//! | [`or_else`] | `None` | (not provided) | `None` | `None` |
252+
//! | [`or_else`] | `None` | (not provided) | `Some(y)` | `Some(y)` |
253+
//! | [`or_else`] | `Some(x)` | (not provided) | (not evaluated) | `Some(x)` |
254+
//!
255+
//! [`and_then`]: Option::and_then
256+
//! [`or_else`]: Option::or_else
257+
//!
258+
//! This is an example of using methods like [`and_then`] and [`or`] in a
259+
//! pipeline of method calls. Early stages of the pipeline pass failure
260+
//! values ([`None`]) through unchanged, and continue processing on
261+
//! success values ([`Some`]). Toward the end, [`or`] substitutes an error
262+
//! message if it receives [`None`].
263+
//!
264+
//! ```
265+
//! # use std::collections::BTreeMap;
266+
//! let mut bt = BTreeMap::new();
267+
//! bt.insert(20u8, "foo");
268+
//! bt.insert(42u8, "bar");
269+
//! let res = vec![0u8, 1, 11, 200, 22]
270+
//! .into_iter()
271+
//! .map(|x| {
272+
//! // `checked_sub()` returns `None` on error
273+
//! x.checked_sub(1)
274+
//! // same with `checked_mul()`
275+
//! .and_then(|x| x.checked_mul(2))
276+
//! // `BTreeMap::get` returns `None` on error
277+
//! .and_then(|x| bt.get(&x))
278+
//! // Substitute an error message if we have `None` so far
279+
//! .or(Some(&"error!"))
280+
//! .copied()
281+
//! // Won't panic because we unconditionally used `Some` above
282+
//! .unwrap()
283+
//! })
284+
//! .collect::<Vec<_>>();
285+
//! assert_eq!(res, ["error!", "error!", "foo", "error!", "bar"]);
286+
//! ```
287+
//!
288+
//! ## Iterating over `Option`
289+
//!
290+
//! An [`Option`] can be iterated over. This can be helpful if you need an
291+
//! iterator that is conditionally empty. The iterator will either produce
292+
//! a single value (when the [`Option`] is [`Some`]), or produce no values
293+
//! (when the [`Option`] is [`None`]). For example, [`into_iter`] acts like
294+
//! [`once(v)`] if the [`Option`] is [`Some(v)`], and like [`empty()`] if
295+
//! the [`Option`] is [`None`].
296+
//!
297+
//! [`Some(v)`]: Some
298+
//! [`empty()`]: crate::iter::empty
299+
//! [`once(v)`]: crate::iter::once
300+
//!
301+
//! Iterators over [`Option<T>`] come in three types:
302+
//!
303+
//! * [`into_iter`] consumes the [`Option`] and produces the contained
304+
//! value
305+
//! * [`iter`] produces an immutable reference of type `&T` to the
306+
//! contained value
307+
//! * [`iter_mut`] produces a mutable reference of type `&mut T` to the
308+
//! contained value
309+
//!
310+
//! [`into_iter`]: Option::into_iter
311+
//! [`iter`]: Option::iter
312+
//! [`iter_mut`]: Option::iter_mut
313+
//!
314+
//! An iterator over [`Option`] can be useful when chaining iterators, for
315+
//! example, to conditionally insert items. (It's not always necessary to
316+
//! explicitly call an iterator constructor: many [`Iterator`] methods that
317+
//! accept other iterators will also accept iterable types that implement
318+
//! [`IntoIterator`], which includes [`Option`].)
319+
//!
320+
//! ```
321+
//! let yep = Some(42);
322+
//! let nope = None;
323+
//! // chain() already calls into_iter(), so we don't have to do so
324+
//! let nums: Vec<i32> = (0..4).chain(yep).chain(4..8).collect();
325+
//! assert_eq!(nums, [0, 1, 2, 3, 42, 4, 5, 6, 7]);
326+
//! let nums: Vec<i32> = (0..4).chain(nope).chain(4..8).collect();
327+
//! assert_eq!(nums, [0, 1, 2, 3, 4, 5, 6, 7]);
328+
//! ```
329+
//!
330+
//! One reason to chain iterators in this way is that a function returning
331+
//! `impl Iterator` must have all possible return values be of the same
332+
//! concrete type. Chaining an iterated [`Option`] can help with that.
333+
//!
334+
//! ```
335+
//! fn make_iter(do_insert: bool) -> impl Iterator<Item = i32> {
336+
//! // Explicit returns to illustrate return types matching
337+
//! match do_insert {
338+
//! true => return (0..4).chain(Some(42)).chain(4..8),
339+
//! false => return (0..4).chain(None).chain(4..8),
340+
//! }
341+
//! }
342+
//! println!("{:?}", make_iter(true).collect::<Vec<_>>());
343+
//! println!("{:?}", make_iter(false).collect::<Vec<_>>());
344+
//! ```
345+
//!
346+
//! If we try to do the same thing, but using [`once()`] and [`empty()`],
347+
//! we can't return `impl Iterator` anymore because the concrete types of
348+
//! the return values differ.
349+
//!
350+
//! [`empty()`]: crate::iter::empty
351+
//! [`once()`]: crate::iter::once
352+
//!
353+
//! ```compile_fail,E0308
354+
//! # use std::iter::{empty, once};
355+
//! // This won't compile because all possible returns from the function
356+
//! // must have the same concrete type.
357+
//! fn make_iter(do_insert: bool) -> impl Iterator<Item = i32> {
358+
//! // Explicit returns to illustrate return types not matching
359+
//! match x {
360+
//! true => return (0..4).chain(once(42)).chain(4..8),
361+
//! false => return (0..4).chain(empty()).chain(4..8),
362+
//! }
363+
//! }
364+
//! ```
365+
//!
366+
//! ## Collecting into `Option`
367+
//!
368+
//! [`Option`] implements the [`FromIterator`][impl-FromIterator] trait,
369+
//! which allows an iterator over [`Option`] values to be collected into an
370+
//! [`Option`] of a collection of each contained value of the original
371+
//! [`Option`] values, or [`None`] if any of the elements was [`None`].
372+
//!
373+
//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E
374+
//!
375+
//! ```
376+
//! let v = vec![Some(2), Some(4), None, Some(8)];
377+
//! let res: Option<Vec<_>> = v.into_iter().collect();
378+
//! assert_eq!(res, None);
379+
//! let v = vec![Some(2), Some(4), Some(8)];
380+
//! let res: Option<Vec<_>> = v.into_iter().collect();
381+
//! assert_eq!(res, Some(vec![2, 4, 8]));
382+
//! ```
383+
//!
384+
//! [`Option`] also implements the [`Product`][impl-Product] and
385+
//! [`Sum`][impl-Sum] traits, allowing an iterator over [`Option`] values
386+
//! to provide the [`product`][Iterator::product] and
387+
//! [`sum`][Iterator::sum] methods.
388+
//!
389+
//! [impl-Product]: Option#impl-Product%3COption%3CU%3E%3E
390+
//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E
391+
//!
392+
//! ```
393+
//! let v = vec![None, Some(1), Some(2), Some(3)];
394+
//! let res: Option<i32> = v.into_iter().sum();
395+
//! assert_eq!(res, None);
396+
//! let v = vec![Some(1), Some(2), Some(21)];
397+
//! let res: Option<i32> = v.into_iter().product();
398+
//! assert_eq!(res, Some(42));
399+
//! ```
400+
//!
401+
//! ## Modifying an [`Option`] in-place
402+
//!
403+
//! These methods return a mutable reference to the contained value of an
404+
//! [`Option<T>`]:
405+
//!
406+
//! * [`insert`] inserts a value, dropping any old contents
407+
//! * [`get_or_insert`] gets the current value, inserting a provided
408+
//! default value if it is [`None`]
409+
//! * [`get_or_insert_default`] gets the current value, inserting the
410+
//! default value of type `T` (which must implement [`Default`]) if it is
411+
//! [`None`]
412+
//! * [`get_or_insert_with`] gets the current value, inserting a default
413+
//! computed by the provided function if it is [`None`]
414+
//!
415+
//! [`get_or_insert`]: Option::get_or_insert
416+
//! [`get_or_insert_default`]: Option::get_or_insert_default
417+
//! [`get_or_insert_with`]: Option::get_or_insert_with
418+
//! [`insert`]: Option::insert
419+
//!
420+
//! These methods transfer ownership of the contained value of an
421+
//! [`Option`]:
422+
//!
423+
//! * [`take`] takes ownership of the contained value of an [`Option`], if
424+
//! any, replacing the [`Option`] with [`None`]
425+
//! * [`replace`] takes ownership of the contained value of an [`Option`],
426+
//! if any, replacing the [`Option`] with a [`Some`] containing the
427+
//! provided value
428+
//!
429+
//! [`replace`]: Option::replace
430+
//! [`take`]: Option::take
431+
//!
93432
//! # Examples
94433
//!
95434
//! Basic pattern matching on [`Option`]:
@@ -141,11 +480,6 @@
141480
//! None => println!("there are no animals :("),
142481
//! }
143482
//! ```
144-
//!
145-
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
146-
//! [`Box<U>`]: ../../std/boxed/struct.Box.html
147-
//! [`num::NonZero*`]: crate::num
148-
//! [`ptr::NonNull<U>`]: crate::ptr::NonNull
149483
150484
#![stable(feature = "rust1", since = "1.0.0")]
151485

0 commit comments

Comments
 (0)