pub enum ControlFlow<B, C = ()> {
Continue(C),
Break(B),
}Expand description
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.
Similar to Option and Result, this enum can be used with the ? operator
to return immediately if the Break variant is present or otherwise continue normally
with the value inside the Continue variant.
ยงExamples
Early-exiting from Iterator::try_for_each:
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:
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, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
if let Some(left) = &self.left {
left.traverse_inorder(f)?;
}
f(&self.value)?;
if let Some(right) = &self.right {
right.traverse_inorder(f)?;
}
ControlFlow::Continue(())
}
fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
Some(Box::new(Self { value, left: None, right: None }))
}
}
let node = TreeNode {
value: 0,
left: TreeNode::leaf(1),
right: Some(Box::new(TreeNode {
value: -1,
left: TreeNode::leaf(5),
right: TreeNode::leaf(2),
}))
};
let mut sum = 0;
let res = node.traverse_inorder(&mut |val| {
if *val < 0 {
ControlFlow::Break(*val)
} else {
sum += *val;
ControlFlow::Continue(())
}
});
assert_eq!(res, ControlFlow::Break(-1));
assert_eq!(sum, 6);Variantsยง
Continue(C)
Move on to the next phase of the operation as normal.
Break(B)
Exit the operation without running subsequent phases.
Implementationsยง
Sourceยงimpl<B, C> ControlFlow<B, C>
impl<B, C> ControlFlow<B, C>
1.59.0 (const: 1.95.0) ยท Sourcepub const fn is_break(&self) -> bool
pub const fn is_break(&self) -> bool
Returns true if this is a Break variant.
ยงExamples
1.59.0 (const: 1.95.0) ยท Sourcepub const fn is_continue(&self) -> bool
pub const fn is_continue(&self) -> bool
Returns true if this is a Continue variant.
ยงExamples
1.83.0 (const: unstable) ยท Sourcepub fn break_value(self) -> Option<B>
pub fn break_value(self) -> Option<B>
Converts the ControlFlow into an Option which is Some if the
ControlFlow was Break and None otherwise.
ยงExamples
1.96.0 (const: 1.96.0) ยท Sourcepub const fn break_ok(self) -> Result<B, C>
pub const fn break_ok(self) -> Result<B, C>
Converts the ControlFlow into a Result which is Ok if the
ControlFlow was Break and Err if otherwise.
ยงExamples
use std::ops::ControlFlow;
struct TreeNode<T> {
value: T,
left: Option<Box<TreeNode<T>>>,
right: Option<Box<TreeNode<T>>>,
}
impl<T> TreeNode<T> {
fn find<'a>(&'a self, mut predicate: impl FnMut(&T) -> bool) -> Result<&'a T, ()> {
let mut f = |t: &'a T| -> ControlFlow<&'a T> {
if predicate(t) {
ControlFlow::Break(t)
} else {
ControlFlow::Continue(())
}
};
self.traverse_inorder(&mut f).break_ok()
}
fn traverse_inorder<'a, B>(
&'a self,
f: &mut impl FnMut(&'a T) -> ControlFlow<B>,
) -> ControlFlow<B> {
if let Some(left) = &self.left {
left.traverse_inorder(f)?;
}
f(&self.value)?;
if let Some(right) = &self.right {
right.traverse_inorder(f)?;
}
ControlFlow::Continue(())
}
fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
Some(Box::new(Self {
value,
left: None,
right: None,
}))
}
}
let node = TreeNode {
value: 0,
left: TreeNode::leaf(1),
right: Some(Box::new(TreeNode {
value: -1,
left: TreeNode::leaf(5),
right: TreeNode::leaf(2),
})),
};
let res = node.find(|val: &i32| *val > 3);
assert_eq!(res, Ok(&5));1.83.0 (const: unstable) ยท Sourcepub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>where
F: FnOnce(B) -> T,
pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>where
F: FnOnce(B) -> T,
Maps ControlFlow<B, C> to ControlFlow<T, C> by applying a function
to the break value in case it exists.
1.83.0 (const: unstable) ยท Sourcepub fn continue_value(self) -> Option<C>
pub fn continue_value(self) -> Option<C>
Converts the ControlFlow into an Option which is Some if the
ControlFlow was Continue and None otherwise.
ยงExamples
1.96.0 (const: 1.96.0) ยท Sourcepub const fn continue_ok(self) -> Result<C, B>
pub const fn continue_ok(self) -> Result<C, B>
Converts the ControlFlow into a Result which is Ok if the
ControlFlow was Continue and Err if otherwise.
ยงExamples
use std::ops::ControlFlow;
struct TreeNode<T> {
value: T,
left: Option<Box<TreeNode<T>>>,
right: Option<Box<TreeNode<T>>>,
}
impl<T> TreeNode<T> {
fn validate<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> Result<(), B> {
self.traverse_inorder(f).continue_ok()
}
fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
if let Some(left) = &self.left {
left.traverse_inorder(f)?;
}
f(&self.value)?;
if let Some(right) = &self.right {
right.traverse_inorder(f)?;
}
ControlFlow::Continue(())
}
fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
Some(Box::new(Self {
value,
left: None,
right: None,
}))
}
}
let node = TreeNode {
value: 0,
left: TreeNode::leaf(1),
right: Some(Box::new(TreeNode {
value: -1,
left: TreeNode::leaf(5),
right: TreeNode::leaf(2),
})),
};
let res = node.validate(&mut |val| {
if *val < 0 {
return ControlFlow::Break("negative value detected");
}
if *val > 4 {
return ControlFlow::Break("too big value detected");
}
ControlFlow::Continue(())
});
assert_eq!(res, Err("too big value detected"));1.83.0 (const: unstable) ยท Sourcepub fn map_continue<T, F>(self, f: F) -> ControlFlow<B, T>where
F: FnOnce(C) -> T,
pub fn map_continue<T, F>(self, f: F) -> ControlFlow<B, T>where
F: FnOnce(C) -> T,
Maps ControlFlow<B, C> to ControlFlow<B, T> by applying a function
to the continue value in case it exists.
Sourceยงimpl<T> ControlFlow<T, T>
impl<T> ControlFlow<T, T>
Sourcepub const fn into_value(self) -> T
๐ฌThis is a nightly-only experimental API. (control_flow_into_value #137461)
pub const fn into_value(self) -> T
control_flow_into_value #137461)Extracts the value T that is wrapped by ControlFlow<T, T>.
ยงExamples
Trait Implementationsยง
1.55.0 (const: unstable) ยท Sourceยงimpl<B, C> Clone for ControlFlow<B, C>
impl<B, C> Clone for ControlFlow<B, C>
Sourceยงfn clone(&self) -> ControlFlow<B, C>
fn clone(&self) -> ControlFlow<B, C>
1.0.0 ยท Sourceยงfn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more1.55.0 ยท Sourceยงimpl<B, C> Debug for ControlFlow<B, C>
impl<B, C> Debug for ControlFlow<B, C>
Sourceยงimpl<B, C> FromResidual<ControlFlow<B, Infallible>> for ControlFlow<B, C>
impl<B, C> FromResidual<ControlFlow<B, Infallible>> for ControlFlow<B, C>
Sourceยงfn from_residual(residual: ControlFlow<B, Infallible>) -> ControlFlow<B, C>
fn from_residual(residual: ControlFlow<B, Infallible>) -> ControlFlow<B, C>
try_trait_v2 #84277)Residual type. Read more1.55.0 ยท Sourceยงimpl<B, C> Hash for ControlFlow<B, C>
impl<B, C> Hash for ControlFlow<B, C>
1.55.0 (const: unstable) ยท Sourceยงimpl<B, C> PartialEq for ControlFlow<B, C>
impl<B, C> PartialEq for ControlFlow<B, C>
Sourceยงimpl<B, C> Residual<C> for ControlFlow<B, Infallible>
impl<B, C> Residual<C> for ControlFlow<B, Infallible>
Sourceยงtype TryType = ControlFlow<B, C>
type TryType = ControlFlow<B, C>
try_trait_v2_residual #91285)Sourceยงimpl<B, C> Try for ControlFlow<B, C>
impl<B, C> Try for ControlFlow<B, C>
Sourceยงtype Output = C
type Output = C
try_trait_v2 #84277)? when not short-circuiting.Sourceยงtype Residual = ControlFlow<B, Infallible>
type Residual = ControlFlow<B, Infallible>
try_trait_v2 #84277)FromResidual::from_residual
as part of ? when short-circuiting. Read moreSourceยงfn from_output(output: <ControlFlow<B, C> as Try>::Output) -> ControlFlow<B, C>
fn from_output(output: <ControlFlow<B, C> as Try>::Output) -> ControlFlow<B, C>
try_trait_v2 #84277)Output type. Read moreSourceยงfn branch(
self,
) -> ControlFlow<<ControlFlow<B, C> as Try>::Residual, <ControlFlow<B, C> as Try>::Output>
fn branch( self, ) -> ControlFlow<<ControlFlow<B, C> as Try>::Residual, <ControlFlow<B, C> as Try>::Output>
try_trait_v2 #84277)? to decide whether the operator should produce a value
(because this returned ControlFlow::Continue)
or propagate a value back to the caller
(because this returned ControlFlow::Break). Read more