特征的生命周期作为返回值

问题描述 投票:0回答:3

我想通过返回

impl trait
来隐藏从 create 函数返回的实际实现,如
create_trait()
中所示。这怎么办?

trait Names<'a> {
    fn names(&'a self) -> &Vec<&'a str>;
}

struct NamesImpl<'b> {
    names: Vec<&'b str>,
}

impl<'c> Names<'c> for NamesImpl<'c> {
    fn names(&'c self) -> &Vec<&'c str> {
        &self.names
    }
}

fn create_impl<'i>() -> NamesImpl<'i> {
    NamesImpl {
        names: vec!["Hello", "world"],
    }
}

#[allow(dead_code)]
fn create_trait<'t>() -> impl Names<'t> {
    NamesImpl {
        names: vec!["Hello", "world"],
    }
}

fn main() {
    let names_impl = create_impl();
    println!("Names: {:?}", names_impl.names());

    //This doesn't compile, see error below
    let names_trait = create_trait();
    println!("Names: {:?}", names_trait.names());
}

我无法理解以下编译错误。为什么它可以与

create_impl()
一起使用,但不能与
create_trait()
一起使用?

error[E0597]: `names_trait` does not live long enough
  --> src/main.rs:34:29
   |
34 |     println!("Names: {:?}", names_trait.names());
   |                             ^^^^^^^^^^^ borrowed value does not live long enough
35 | }
   | -
   | |
   | `names_trait` dropped here while still borrowed
   | borrow might be used here, when `names_trait` is dropped and runs the destructor for type `impl Names<'_>`
rust traits lifetime borrow-checker borrowing
3个回答
4
投票

在 Rust 中使用生命周期的一般经验法则是,如果您不知道自己在做什么,请让编译器为您推断正确的生命周期。一旦您获得更多经验,您就会了解何时“实际上”需要使用显式生命周期注释,但您的示例不是这些情况之一。我可以通过删除所有不必要的生命周期注释来编译它: trait Names { fn names(&self) -> &Vec<&str>; } struct NamesImpl<'a> { names: Vec<&'a str>, } impl Names for NamesImpl<'_> { fn names(&self) -> &Vec<&str> { &self.names } } fn create_impl() -> NamesImpl<'static> { NamesImpl { names: vec!["Hello", "world"] } } fn create_trait() -> impl Names { NamesImpl { names: vec!["Hello", "world"] } } fn main() { let names_impl = create_impl(); println!("Names: {:?}", names_impl.names()); // compiles let names_trait = create_trait(); println!("Names: {:?}", names_trait.names()); }

游乐场

为了确定哪些生命周期注释是不必要的,我首先

删除所有注释

,然后仅将生命周期注释添加回编译器特别要求我添加的区域。


1
投票
常见的 Rust 终身误解

(谢谢椒盐锤!)中的这一部分让我大开眼界。它让我看到在这个建筑中 trait Names<'a> { fn names(&'a self) -> &Vec<&'a str>; }

调用 
names()

将在其剩余生命周期中借用该结构。

使用显式生命周期注释在原始代码中纠正此问题是可能的,但结果远非完美。我只是尝试这样做,试图更好地理解“为什么”。

trait Names<'a : 'f, 'f> { fn names(&self) -> &Vec<&'f str>; } struct NamesImpl<'b> { names: Vec<&'b str>, } impl <'c : 'f, 'f> Names<'c, 'f> for NamesImpl<'c> { fn names(&self) -> &Vec<&'f str> { &self.names } } fn create_impl<'i : 'f, 'f>() -> NamesImpl<'i> { NamesImpl{names: vec!["Hello", "world"]} } #[allow(dead_code)] fn create_trait<'t : 'f, 'f>() -> impl Names<'t, 'f> { NamesImpl{names: vec!["Hello", "world"]} } fn main() { let names_impl = create_impl(); println!("Names: {:?}", names_impl.names()); //This compiles let names_trait = create_trait(); println!("Names: {:?}", names_trait.names()); }

结论:遵循Shepmaster的建议


0
投票
impl Names<'t>

)时,这个问题与滴胶问题有关,并且 Rust 编译器必须决定在给定签名的情况下使用生命周期参数实际是什么。

这是 GAT 的另一个类似问题,在通用测试函数的上下文中它也是不透明类型。 (

方差问题第 1 部分 - 在 Rust 中创建 Wayland 合成器工具箱的冒险

,以及精确解释 NLL 与 dropglue?特征上的生命周期参数 - 帮助 - Rust 编程语言论坛 还要注意以下事实的细微差别:

Trait<'a>

是生命周期不变的

'a
,但结构是协变的。
具体针对操作员的问题,似乎虽然是完全不透明的类型,但返回的 

't

的生命周期参数必须比返回值的整个存在时间更长,直到它被删除。然而,

impl Names<'t>
方法声称在同一段时间内借用 self,但我们无法提供。
names
我自己仍然对这个问题感到怀疑,因为直到我搜索并进入这个主题之前我还没有找到任何相关文档。 (试图理解类似的 GAT 滴胶问题)。如果我有任何遗漏或错误,欢迎更正和提供材料。

但有一点很清楚,他们是完全正确的,只需去掉 
//This doesn't compile, see error below let names_trait = create_trait(); println!("Names: {:?}", names_trait.names()); --> projects/temp/src/main.rs:34:29 | 33 | let names_trait = create_trait(); | ----------- binding `names_trait` declared here 34 | println!("Names: {:?}", names_trait.names()); | ^^^^^^^^^^^ borrowed value does not live long enough ... 37 | } | - | | // EDITED: drop(names_trait) | `names_trait` dropped here while still borrowed | // EDITED: <---- 't ended here, for which in names_trait.names() the names_trait should be borrowed | borrow might be used here, when `names_trait` is dropped and runs the destructor for type `impl Names<'_>`

那个无用的生命周期参数,因为

trait Names<'a>

只自己参与

'a
方法的契约,将其与实现者的生命周期参数绑定是多余的或特质的生命周期参数。
或者至少,如果你想保留它,就拥有它。
names

© www.soinside.com 2019 - 2024. All rights reserved.