简体   繁体   English

包含多态结构的动态特征 Vec 中的模棱两可的错误

[英]Ambiguous error in dynamic trait Vec containing polymorphic structs

I'm a bit confused by the error messaging of rust. rust 的错误消息让我有点困惑。 Consider the following code (it doesn't make much sense in this context; the return type of foo could easily be changed to Vec<Box<dyn MyTrait + 'a>> which makes much more sense, but in the context if the complete code base this return type does make sense).考虑以下代码(在这种情况下没有多大意义; foo 的返回类型可以很容易地更改为Vec<Box<dyn MyTrait + 'a>>这更有意义,但在上下文中,如果完整此返回类型的代码库确实有意义)。

trait MyTrait {
    fn foo<'a>(&self) -> Vec<Box<dyn MyTrait + 'a>>;
}

#[derive(Clone)]
struct MyStruct<T> {
    type_parameter: T,
}

impl <T: Clone> MyTrait for MyStruct<T> {
    fn foo<'a>(&self) -> Vec<Box<dyn MyTrait + 'a>> {
        let foos: Vec<Box<dyn MyTrait + 'a>> = Vec::new();
        
        for i in 0..10 {
            let foo = Box::new(self.clone());
            foos.push(foo);
        }
        
        foos
    }
}

The problem with this code is that the type parameter T in MyStruct<T> can be outlived by 'a .这段代码的问题是MyStruct<T>中的类型参数T可以被'a延长。 When compiling this code the error message I receive is编译此代码时,我收到的错误消息是

error[E0309]: the parameter type `T` may not live long enough
  --> src/main.rs:20:23
   |
14 | impl <T: Clone> MyTrait for MyStruct<T> {
   |       -- help: consider adding an explicit lifetime bound...: `T: 'a +`
...
20 |             foos.push(foo);
   |                       ^^^ ...so that the type `MyStruct<T>` will meet its required lifetime bounds

It states that the type parameter T can be supplemented with the 'a lifetime bound.它指出类型参数T可以用'a alifetime bound 来补充。 However if i try to do this the compiler states that 'a is an undefined lifetime bound, and if I declare 'a it says that 'a is shadowed and I receive the same error as above.但是,如果我尝试这样做,编译器会声明'a是一个未定义的生命周期界限,如果我声明 'a 它会说'a被遮蔽并且我收到与上述相同的错误。 Is there any way I can fix this code or have I reached a limitation of rust?有什么办法可以修复此代码,或者我是否达到了 rust 的限制?

If you'd like to play around with the code, here is a playground https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9e490e98f94e98cde3b9db1ac28ee4a5如果你想玩弄代码,这里是一个操场https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9e490e98f94e98cde3b9db1ac28ee4a5

The declaration of foo doesn't really make sense: foo的声明并没有真正的意义:

fn foo<'a>(&self) -> Vec<Box<dyn MyTrait + 'a>>;

means that whoever calls the function can choose any lifetime 'a they want and get a vector of objects with this lifetime.意味着任何调用 function 的人都可以选择他们想要'a任何生命周期,并获得具有此生命周期的对象向量。 How would that work?那将如何运作? Either the returned objects are owned by the struct and their lifetime must be linked to that of the struct, or ownership will be passed to the caller and there is no need for an explicit lifetime.返回的对象要么归结构所有,并且它们的生命周期必须链接到结构的生命周期,要么所有权将传递给调用者,并且不需要显式的生命周期。

It is much more likely that the lifetime should be linked to the struct, either with:生命周期更有可能与结构相关联,或者使用:

fn foo<'a>(&'a self) -> Vec<Box<dyn MyTrait + 'a>>;
         // ^^ add this

Playground 操场

Or by making the whole trait generic over the lifetime:或者通过使整个特征在整个生命周期中通用:

trait MyTrait<'a> {
    fn foo(&self) -> Vec<Box<dyn MyTrait + 'a>>;
}

#[derive(Clone)]
struct MyStruct<T> {
    type_parameter: T,
}

impl <'a, T: Clone + 'a> MyTrait<'a> for MyStruct<T> {
    fn foo(&self) -> Vec<Box<dyn MyTrait + 'a>> {
        let mut foos: Vec<Box<dyn MyTrait + 'a>> = Vec::new();
        
        for i in 0..10 {
            let foo = Box::new(self.clone());
            foos.push(foo);
        }
        
        foos
    }
}

Playground 操场

Simple solution with minimal lifetime syntax具有最少生命周期语法的简单解决方案

One fix for this could be to use the 'static bound on T as below.解决此问题的一种方法是使用T上的'static边界,如下所示。 What this indicates is the impl for MyStruct accepts any type T whose fields (if any) hold either only owned data, or references with a static lifetime.这表明MyStructimpl接受任何类型T ,其字段(如果有)仅包含拥有的数据,或具有 static 生命周期的引用。

Judging from your use of the Clone bound on T , I sense that you intend for MyStruct to own T and where T needs to be used by other objects, it will be cloned and subsequently owned by them.从您对T上的Clone绑定的使用来看,我感觉您打算让MyStruct拥有T并且T需要由其他对象使用,它将被克隆并随后由它们拥有。

For a good discussion very helpful in understanding the nuances of lifetimes, click here .要进行很好的讨论,对理解生命的细微差别很有帮助,请单击此处 An applicable excerpt from this article that talks about the differences between &'static T vs. T: 'static :本文的适用摘录讨论了&'static TT: 'static之间的区别:

... a type with a 'static lifetime is different from a type bounded by a 'static lifetime. ...具有 'static 生命周期的类型与受 'static 生命周期限制的类型不同。 The latter can be dynamically allocated at run-time, can be safely and freely mutated, can be dropped, and can live for arbitrary durations.后者可以在运行时动态分配,可以安全且自由地变异,可以删除,并且可以存在任意时间。

Another applicable reference on 'static as a trait bound is from this section in Rust By Example :关于 'static 作为 trait bound 的另一个适用参考来自Rust 中的本节示例

As a trait bound, it means the type does not contain any non-static references.作为 trait bound,这意味着该类型不包含任何非静态引用。 Eg.例如。 the receiver can hold on to the type for as long as they want and it will never become invalid until they drop it.接收者可以随心所欲地保留该类型,并且在他们丢弃它之前它永远不会变得无效。

pub trait MyTrait {
    fn get_vec(&self) -> Vec<Box<dyn MyTrait>>;
}

#[derive(Clone)]
pub struct MyStruct<T> {
    type_parameter: T,
}

impl<T: 'static + Clone> MyTrait for MyStruct<T> {

    fn get_vec(&self) -> Vec<Box<dyn MyTrait>> 
    {
        let mut foos: Vec<Box<dyn MyTrait>> = Vec::new();
        
        for i in 0..10 {
            foos.push(Box::new(self.clone()));
        }
        foos
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM