【问题标题】:How can I return None from a function that borrows from it's argument, or avoid needing to?如何从借用其参数的函数中返回 None 或避免需要这样做?
【发布时间】:2015-04-25 07:13:03
【问题描述】:

我有一个选项切片,并给定一个值,如果该值是切片中的有效索引,我想使用该索引处的值,否则使用None

现在,值需要能够被重用,所以我想我想从我的切片中借用,而不是移动...注意 Foo 没有实现 Copy 特征,我更愿意保留就这样吧。

我需要经常这样做,所以返回&Option<Foo> 的函数似乎是合适的,并添加了生命周期说明符,因为显然返回值不应该超过它借用的切片。这导致我:

fn get_or_none<'a>(data: &'a [Option<Foo>], bar: u8) -> &'a Option<Foo> {
  match bar as usize {
    idx if idx < data.len() => &data[idx],
    _ => &None // obviously can't work
  }
}

这显然是错误的。我现在可以作弊,因为我知道对于这个特定的应用程序,切片中的第一个值将始终为 None(可以这么说,这是我的数据的一个属性),但这只是在避免问题。

我应该怎么做?

【问题讨论】:

    标签: rust


    【解决方案1】:

    您可以采取以下几种方法:

    1. 添加另一层Optionness,返回Option&lt;&amp;Option&lt;Foo&gt;&gt;。我猜你不想这样做。

    2. 返回 Option&lt;&amp;Foo&gt; 而不是 &amp;Option&lt;Foo&gt;

      fn get_or_none(data: &[Option<Foo>], bar: u8) -> Option<&Foo> {
          match data.get(bar as usize) {
              Some(&Some(ref foo)) => Some(foo),
              _ => None,
          }
      }
      
    3. 将合适的None 存储为静态并返回对它的引用。它的生命周期是'static(只要Foo'static),所以对它的引用可以缩短为'a 没有问题。

      static NO_FOO: Option<Foo> = None;
      
      fn get_or_none(data: &[Option<Foo>], bar: u8) -> &Option<Foo> {
          data.get(bar as usize).unwrap_or(&NO_FOO)
      }
      

    【讨论】:

    • 1.看起来像垃圾。 3 听起来像一个反模式。 2. 看起来不错 - 您选择使用嵌套的 Somes 解构 data.get() 是否被认为更惯用?我发现检查长度更容易理解,但这可能是因为我是 Rust 新手。
    • 根据Option&lt;Foo&gt; 的语义,这三个中的任何一个都可能是最合适的(好吧,少三个),尽管我倾向于认为第二个是最好的.顺便说一句,它可以写成data.get(bar as usize).and_then(|x| x.as_ref())。我只选择感觉最好的,在第二种情况下,我觉得更复杂的模式比and_then 加上as_ref 更好更清晰,而在第三种情况下,我觉得unwrap_or 是一个不错的选择。恐怕这都是相当主观的。
    • 感谢您,我刚刚发现了and_then()or_else()。非常便利。我同意在这种情况下,and_then 的情况不如 match 子句那么明显,但正如你所说,这是主观的。
    【解决方案2】:

    由于您显然不需要通过此函数更改切片,因此另一种方法是将您的返回类型从 &amp;'a Option&lt;Foo&gt; 切换到 Option&lt;&amp;'a Foo&gt;。这样,您返回None 不会有任何问题。

    为此,您可以使用Option::as_ref(..) 方法,该方法允许您将&amp;Option&lt;Foo&gt; 转换为Option&lt;&amp;Foo&gt;

    最后,你有:

    fn get_or_none<'a>(data: &'a [Option<Foo>], bar: u8) -> Option<&'a Foo> {
        match bar as usize {
            idx if idx < data.len() => data[idx].as_ref(),
            _ => None
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-27
      • 2020-03-28
      • 2013-02-17
      • 2021-12-10
      • 2021-03-01
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多