如何将Option<T>惯用地转换为Result<T, ()>?

13

我是Rust的新手!将Option<T>转换为Result<T, ()>的最佳方法是什么?

TryFrom特性似乎很普遍并返回一个Result。流行的num_traits' NumCast有许多转换,但它们都返回一个Option<T>。同样,像Rust标准库中的NonZeroI32这样的NonZero*构造函数也是如此。然后我注意到NumCast实现了一个返回Option<T>from(),所以我认为它可能在一般情况下有一种非标准的做法,但接着我看到了NonZero*的实现,对那个想法产生了疑问。

无论如何,从Options转换为Results似乎很频繁,但我还没有找到一个简洁的方法。例如:

/// Add common conversion from an i32 to a non-zero i32.
impl TryFrom<Container<i32>> for Container<NonZeroI32> {
  type Error = ();
  fn try_from(container: Container<i32>) -> Result<Self, ()> {
    // NonZeroI32::new() returns an Option not a Result. Try a helper.
    Ok(Self(option_to_result(NonZeroI32::new(container.0))?))
  }
}

/// Helper function to convert from an Option to a Result (both types are
/// foreign and so is From).
fn option_to_result<T>(option: Option<T>) -> Result<T, ()> {
  if let Some(some) = option {
    Ok(some)
  } else {
    Err(())
  }
}

/// Add another common conversion from an i32 to an i16.
impl TryFrom<Container<i32>> for Container<i16> {
  type Error = ();
  fn try_from(container: Container<i32>) -> Result<Self, ()> {
    // NumCast::from() also returns an Option not a Result. Try map_or() instead
    // of the helper.
    Ok(Self(NumCast::from(container.0).map_or(Err(()), |x| Ok(x))?))
  }
}

(以上示例在Rust Playground中。)
这些NumCast、NonZero*和TryFrom转换似乎很常见,但我的方法感觉笨拙,好像我正在将Option和Result类型相互对抗。我在这些转换中挣扎,并且也错过了给定Result<T>感觉相似的Option类型的基本要点。
那么,在Rust 2018中将Option<T>转换为Result<T,()>的惯用方法是什么?
1个回答

23

Optionok_or方法,可用于正是这个(实际上,更为广泛的情况也适用),但你的请求也适用于此:

fn option_to_result<T>(option: Option<T>) -> Result<T, ()> {
  option.ok_or(())
}

改进后的代码测试平台


1
谢谢!我不确定我怎么会错过这个,但现在找起来会很容易! - Stephen Niedzielski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接