【问题标题】:How do I borrow a reference to what is inside an Option<T>?如何借用对 Option<T> 内部内容的引用?
【发布时间】:2014-03-09 12:22:29
【问题描述】:

如何从Option 中提取引用并将其与调用者的特定生命周期一起传回?

具体来说,我想从包含Option&lt;Box&lt;Foo&gt;&gt;Bar 中借用对Box&lt;Foo&gt; 的引用。我以为我能做到:

impl Bar {
    fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
        match self.data {
            Some(e) => Ok(&e),
            None => Err(BarErr::Nope),
        }
    }
}

...但这会导致:

error: `e` does not live long enough
  --> src/main.rs:17:28
   |
17 |             Some(e) => Ok(&e),
   |                            ^ does not live long enough
18 |             None => Err(BarErr::Nope),
19 |         }
   |         - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 15:54...
  --> src/main.rs:15:55
   |
15 |       fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
   |  _______________________________________________________^ starting here...
16 | |         match self.data {
17 | |             Some(e) => Ok(&e),
18 | |             None => Err(BarErr::Nope),
19 | |         }
20 | |     }
   | |_____^ ...ending here

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:16:15
   |
16 |         match self.data {
   |               ^^^^ cannot move out of borrowed content
17 |             Some(e) => Ok(&e),
   |                  - hint: to prevent move, use `ref e` or `ref mut e`

嗯,好的。也许不吧。看起来我想做的事与Option::as_ref 相关,好像我可以做的:

impl Bar {
    fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
        match self.data {
            Some(e) => Ok(self.data.as_ref()),
            None => Err(BarErr::Nope),
        }
    }
}

...但是,这也不起作用。

我遇到问题的完整代码:

#[derive(Debug)]
struct Foo;

#[derive(Debug)]
struct Bar {
    data: Option<Box<Foo>>,
}

#[derive(Debug)]
enum BarErr {
    Nope,
}

impl Bar {
    fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
        match self.data {
            Some(e) => Ok(&e),
            None => Err(BarErr::Nope),
        }
    }
}

#[test]
fn test_create_indirect() {
    let mut x = Bar { data: Some(Box::new(Foo)) };
    let mut x2 = Bar { data: None };
    {
        let y = x.borrow();
        println!("{:?}", y);
    }
    {
        let z = x2.borrow();
        println!("{:?}", z);
    }
}

我有理由确定我在这里尝试做的事情是有效的。

【问题讨论】:

    标签: rust


    【解决方案1】:

    从 Rust 1.26 开始,符合人体工程学 允许您编写:

    impl Bar {
        fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
            match &self.data {
                Some(e) => Ok(e),
                None => Err(BarErr::Nope),
            }
        }
    }
    

    在此之前,你可以使用Option::as_ref,你只需要早一点使用它:

    impl Bar {
        fn borrow(&self) -> Result<&Box<Foo>, BarErr> {
            self.data.as_ref().ok_or(BarErr::Nope)
        }
    }
    

    有一个可变引用的伴随方法:Option::as_mut:

    impl Bar {
        fn borrow_mut(&mut self) -> Result<&mut Box<Foo>, BarErr> {
            self.data.as_mut().ok_or(BarErr::Nope)
        }
    }
    

    我鼓励删除 Box 包装器。

    从 Rust 1.40 开始,您可以使用 Option::as_deref / Option::as_deref_mut

    impl Bar {
        fn borrow(&self) -> Result<&Foo, BarErr> {
            self.data.as_deref().ok_or(BarErr::Nope)
        }
    
        fn borrow_mut(&mut self) -> Result<&mut Foo, BarErr> {
            self.data.as_deref_mut().ok_or(BarErr::Nope)
        }
    }
    

    在那之前,我可能会使用map

    impl Bar {
        fn borrow(&self) -> Result<&Foo, BarErr> {
            self.data.as_ref().map(|x| &**x).ok_or(BarErr::Nope)
        }
    
        fn borrow_mut(&mut self) -> Result<&mut Foo, BarErr> {
            self.data.as_mut().map(|x| &mut **x).ok_or(BarErr::Nope)
        }
    }
    

    使用符合人体工程学的版本,您可以进行内联映射:

    impl Bar {
        fn borrow(&mut self) -> Result<&Foo, BarErr> {
            match &self.data {
                Some(e) => Ok(&**e),
                None => Err(BarErr::Nope),
            }
        }
    
        fn borrow_mut(&mut self) -> Result<&mut Foo, BarErr> {
            match &mut self.data {
                Some(e) => Ok(&mut **e),
                None => Err(BarErr::Nope),
            }
        }
    }
    

    另见:

    【讨论】:

    • 我相信这应该是公认的答案。不要忘记as_mut。另外,我认为代码不需要&amp;mut
    【解决方案2】:

    首先,你不需要&amp;mut self

    匹配时,应匹配e作为参考。您正在尝试返回 e 的引用,但它的生命周期仅适用于该匹配语句。

    enum BarErr {
        Nope
    }
    
    struct Foo;
    
    struct Bar {
        data: Option<Box<Foo>>
    }
    
    impl Bar {
        fn borrow(&self) -> Result<&Foo, BarErr> {
            match self.data {
                Some(ref x) => Ok(x),
                None => Err(BarErr::Nope)
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-04
      • 2017-05-31
      • 1970-01-01
      • 2020-09-19
      • 1970-01-01
      • 1970-01-01
      • 2021-04-01
      相关资源
      最近更新 更多