Rollup merge of #81849 - scottmcm:control-flow-comments, r=Mark-Simulacrum
Expand the docs for ops::ControlFlow a bit Since I was writing some examples for an RFC anyway. And I almost made the mistake of reordering the variants, so added a note and a test about that.
This commit is contained in:
commit
a63085dc5e
@ -1,13 +1,63 @@
|
||||
use crate::ops::Try;
|
||||
|
||||
/// Used to make try_fold closures more like normal loops
|
||||
/// Used to tell an operation whether it should exit early or go on as usual.
|
||||
///
|
||||
/// This is used when exposing things (like graph traversals or visitors) where
|
||||
/// you want the user to be able to choose whether to exit early.
|
||||
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
|
||||
/// mean again?" -- and allows including a value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Early-exiting from [`Iterator::try_for_each`]:
|
||||
/// ```
|
||||
/// #![feature(control_flow_enum)]
|
||||
/// use std::ops::ControlFlow;
|
||||
///
|
||||
/// let r = (2..100).try_for_each(|x| {
|
||||
/// if 403 % x == 0 {
|
||||
/// return ControlFlow::Break(x)
|
||||
/// }
|
||||
///
|
||||
/// ControlFlow::Continue(())
|
||||
/// });
|
||||
/// assert_eq!(r, ControlFlow::Break(13));
|
||||
/// ```
|
||||
///
|
||||
/// A basic tree traversal:
|
||||
/// ```no_run
|
||||
/// #![feature(control_flow_enum)]
|
||||
/// use std::ops::ControlFlow;
|
||||
///
|
||||
/// pub struct TreeNode<T> {
|
||||
/// value: T,
|
||||
/// left: Option<Box<TreeNode<T>>>,
|
||||
/// right: Option<Box<TreeNode<T>>>,
|
||||
/// }
|
||||
///
|
||||
/// impl<T> TreeNode<T> {
|
||||
/// pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
|
||||
/// if let Some(left) = &self.left {
|
||||
/// left.traverse_inorder(&mut f)?;
|
||||
/// }
|
||||
/// f(&self.value)?;
|
||||
/// if let Some(right) = &self.right {
|
||||
/// right.traverse_inorder(&mut f)?;
|
||||
/// }
|
||||
/// ControlFlow::Continue(())
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ControlFlow<B, C = ()> {
|
||||
/// Continue in the loop, using the given value for the next iteration
|
||||
/// Move on to the next phase of the operation as normal.
|
||||
Continue(C),
|
||||
/// Exit the loop, yielding the given value
|
||||
/// Exit the operation without running subsequent phases.
|
||||
Break(B),
|
||||
// Yes, the order of the variants doesn't match the type parameters.
|
||||
// They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
|
||||
// is a no-op conversion in the `Try` implementation.
|
||||
}
|
||||
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
@ -33,6 +83,16 @@ impl<B, C> Try for ControlFlow<B, C> {
|
||||
|
||||
impl<B, C> ControlFlow<B, C> {
|
||||
/// Returns `true` if this is a `Break` variant.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(control_flow_enum)]
|
||||
/// use std::ops::ControlFlow;
|
||||
///
|
||||
/// assert!(ControlFlow::<i32, String>::Break(3).is_break());
|
||||
/// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
pub fn is_break(&self) -> bool {
|
||||
@ -40,6 +100,16 @@ impl<B, C> ControlFlow<B, C> {
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a `Continue` variant.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(control_flow_enum)]
|
||||
/// use std::ops::ControlFlow;
|
||||
///
|
||||
/// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
|
||||
/// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
pub fn is_continue(&self) -> bool {
|
||||
@ -48,6 +118,16 @@ impl<B, C> ControlFlow<B, C> {
|
||||
|
||||
/// Converts the `ControlFlow` into an `Option` which is `Some` if the
|
||||
/// `ControlFlow` was `Break` and `None` otherwise.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(control_flow_enum)]
|
||||
/// use std::ops::ControlFlow;
|
||||
///
|
||||
/// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
|
||||
/// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
pub fn break_value(self) -> Option<B> {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#![feature(const_maybe_uninit_assume_init)]
|
||||
#![feature(const_ptr_read)]
|
||||
#![feature(const_ptr_offset)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(core_private_bignum)]
|
||||
#![feature(core_private_diy_float)]
|
||||
|
@ -1,3 +1,5 @@
|
||||
mod control_flow;
|
||||
|
||||
use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
|
18
library/core/tests/ops/control_flow.rs
Normal file
18
library/core/tests/ops/control_flow.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use core::intrinsics::discriminant_value;
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
#[test]
|
||||
fn control_flow_discriminants_match_result() {
|
||||
// This isn't stable surface area, but helps keep `?` cheap between them,
|
||||
// even if LLVM can't always take advantage of it right now.
|
||||
// (Sadly Result and Option are inconsistent, so ControlFlow can't match both.)
|
||||
|
||||
assert_eq!(
|
||||
discriminant_value(&ControlFlow::<i32, i32>::Break(3)),
|
||||
discriminant_value(&Result::<i32, i32>::Err(3)),
|
||||
);
|
||||
assert_eq!(
|
||||
discriminant_value(&ControlFlow::<i32, i32>::Continue(3)),
|
||||
discriminant_value(&Result::<i32, i32>::Ok(3)),
|
||||
);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user