【问题标题】:Returning reference contained in an input wrapper type using AsRef使用 AsRef 返回包含在输入包装类型中的引用
【发布时间】:2021-01-16 15:13:16
【问题描述】:

我有一个围绕 &str 的包装器来维护一个不变量。当我尝试返回一个新的包装器时,该包装器基本上将由参数包装的相同数据包装到函数中 (playground),我得到“无法返回值引用函数参数s

struct MyStrWrapper<'a> {
    raw: &'a str,
}

impl AsRef<str> for MyStrWrapper<'_> {
    fn as_ref(&self) -> &str {
        &self.raw
    }
}

fn my_function<'inp>(s: MyStrWrapper<'inp>) -> MyStrWrapper<'inp> {
    MyStrWrapper {
        raw: &s.as_ref()[1..],
    }
}

索引与错误无关,但当我使用s.raw 而不是通过as_ref() 直接访问成员时,它可以工作。有没有一种好方法可以使rawmy_function 不可见?

【问题讨论】:

  • 在这种情况下,您不能使用AsRef,因为my_function 会消耗s,而as_ref() 返回的内容的生命周期仅存在于my_function 调用期间。因此,当s 被删除时,as_ref() 返回的内容无效。如果你改为借用s,即s: &amp;'imp MyStrWrapper&lt;'imp&gt;,那么你的代码就可以工作了。

标签: generics rust reference lifetime borrow-checker


【解决方案1】:

您可以将s 作为具有相同生命周期的引用传递 (Playground):

fn my_function<'inp>(s: &'inp MyStrWrapper<'inp>) -> MyStrWrapper<'inp> 

然后参考调用:

my_function(&s);

【讨论】:

    【解决方案2】:

    如果主要要求不是使内部raw 字段对my_function 可见,并且您可以在将内部&amp;str 包装在新实例中之前使用原始MyStrWrapper 实例,那么我建议使用From trait 在 MyStrWrapper&amp;str 之间进行转换,并在 my_function 的实现中使用它。示例:

    struct MyStrWrapper<'a> {
        raw: &'a str,
    }
    
    impl<'a> From<MyStrWrapper<'a>> for &'a str {
        fn from(item: MyStrWrapper<'a>) -> Self {
            item.raw
        }
    }
    
    fn my_function<'inp>(s: MyStrWrapper<'inp>) -> MyStrWrapper<'inp> {
        // convert MyStrWrapper into &str without exposing "raw" field to function
        let inner_str = s.into();
        // do whatever you need to do with inner_str here
        // re-wrap inner_str here
        MyStrWrapper {
            raw: inner_str,
        }
    }
    
    fn main() {
        let s = MyStrWrapper {
            raw: "Hello, world!",
        };
        my_function(s);
    }
    

    playground


    如果你真的想从my_function 中隐藏raw,你也可以使用TryFrom trait 实现另一个方向的转换,从&amp;strMyStrWrapper,因为如果不满足不变量。更新示例:

    use std::convert::TryInto;
    use std::convert::TryFrom;
    
    struct MyStrWrapper<'a> {
        raw: &'a str,
    }
    
    impl<'a> From<MyStrWrapper<'a>> for &'a str {
        fn from(item: MyStrWrapper<'a>) -> Self {
            item.raw
        }
    }
    
    #[derive(Debug)]
    enum MyInvariant {
        FailureReason
    }
    
    impl<'a> TryFrom<&'a str> for MyStrWrapper<'a> {
        type Error = MyInvariant;
    
        fn try_from(item: &'a str) -> Result<Self, Self::Error> {
            // check invariant on item
            // if fails return Err(MyInvariant::FailureReason)
            // else
            Ok(MyStrWrapper {
                raw: item
            })
        }
    }
    
    fn my_function<'inp>(s: MyStrWrapper<'inp>) -> MyStrWrapper<'inp> {
        // convert MyStrWrapper into &str without exposing "raw" field to function
        let inner_str: &str = s.into();
        // do whatever you need to do with inner_str here
        // re-wrap inner_str here
        inner_str.try_into().unwrap()
    }
    
    fn main() {
        let s = MyStrWrapper {
            raw: "Hello, world!",
        };
        my_function(s);
    }
    

    playground

    【讨论】:

      猜你喜欢
      • 2020-03-24
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-01
      • 2020-08-25
      • 1970-01-01
      相关资源
      最近更新 更多