代码之家  ›  专栏  ›  技术社区  ›  Wladimir Palant

无法从泛型函数中的引用构造(值的有效期不够长)

  •  0
  • Wladimir Palant  · 技术社区  · 2 年前

    我有一个方法,它接受一些参数,从中创建(解密)一个中间值,并尝试从该中间值构造一个类型实例。只要类型是固定的,就可以正常工作。如果我想通过泛型支持多个类型,我会遇到麻烦。以下是缩小的代码:

    impl Factory
    {
        pub fn get<'a, T>(&'a self, value: &'a str) -> T
            where T: From<&'a str>
        {
            let value_parsed = value.chars().rev().collect::<String>();
            return T::from(&value_parsed);
        }
    }
    

    您可以运行完整的代码 here 。编译会产生以下错误:

    31 |     pub fn get<'a, T>(&'a self, value: &'a str) -> T
       |                -- lifetime `'a` defined here
    ...
    35 |         return T::from(&value_parsed);
       |                --------^^^^^^^^^^^^^-
       |                |       |
       |                |       borrowed value does not live long enough
       |                argument requires that `value_parsed` is borrowed for `'a`
    36 |     }
       |     - `value_parsed` dropped here while still borrowed
    

    正如我所说,使用 Item 在方法中签名而不是泛型类型可以消除此错误。未将引用传递到 T::from() 但移动临时值也是一种选择,但考虑到这一点,这没有什么意义 value_parsed 实际上并没有在这里被消耗,它变得很尴尬,并且与我的代码库的其他部分不一致。

    无论如何我都能确定 value_parsed 寿命够长吗?或者除了在这里不使用参考文献之外,还有其他解决方案吗?

    1 回复  |  直到 2 年前
        1
  •  3
  •   kmdreko    2 年前

    你会使用 higher-rank trait bound 以指示类型 T 可以由具有 任何 寿命,而不是 具体的 用作函数泛型时的生存期:

    pub fn get<T>(&self, value: &str) -> T
        where T: for<'a> From<&'a str>
              // ^^^^^^^
    

    你之前的情况表明 T 可以根据引用构建,其生存期基于 self value 然而,由于 value_parsed 是一个局部变量,对它的引用不能满足生存期约束。

        2
  •  0
  •   Wladimir Palant    2 年前

    事实证明,使用我自己的特质在这里很有效,它不需要我在签名中指定对类型的引用,因此也不需要将一生与特质联系起来:

    trait Get<T>
    {
        fn get(value: &T) -> Self;
    }
    

    利用这种特性,该方法可以编译:

    pub fn get<'a, T>(&'a self, value: &'a str) -> T
        where T: Get<String>
    {
        let value_parsed = value.chars().rev().collect::<String>();
        return T::get(&value_parsed);
    }
    

    我不确定这是否是最好的解决方案,但这个解决方案有效。