【问题标题】:How to fix: value may contain references; add `'static` bound to `T`如何修复:值可能包含引用;添加绑定到“T”的“静态”
【发布时间】:2014-06-23 22:45:46
【问题描述】:

我又一次遇到了我自己似乎无法解决的终身问题。

我有这个特点

pub trait MiddlewareHandler: Clone {
    fn invoke (&self, req: &Request, res: &mut Response) -> bool {
        true
    }

    // we need this because otherwise clone() would be ambiguous
    fn clone_box(&self) -> Box<MiddlewareHandler> { 
        box self.clone() as Box<MiddlewareHandler> 
    }
}

impl MiddlewareHandler for fn (req: &Request, res: &mut Response) -> bool {
    fn invoke(&self, req: &Request, res: &mut Response) -> bool{
        (*self).invoke(req, res)
    }
}

impl Clone for Box<MiddlewareHandler> {
    fn clone(&self) -> Box<MiddlewareHandler> { 
        self.clone_box() 
    }
}

我为fn (req: &amp;Request, res: &amp;mut Response) -&gt; bool 实现的目的是为了能够同时使用accept 轻量级函数和更重的MiddlewareHandler 实现者。

我将它们存储为Vec&lt;Box&lt;MiddlewareHandler&gt;&gt;

pub struct Middleware {
    handlers: Vec<Box<MiddlewareHandler>>
}

现在,问题是,编译器在这里对我大喊大叫:

    pub fn add<T: MiddlewareHandler> (&mut self, handler: T) {
        self.handlers.push(box handler);
    }

上面写着:

error: value may contain references; add `'static` bound to `T`
       self.handlers.push(box handler);

实现应该与这里使用的非常相似:

https://github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67

但是,我似乎看不出区别:-/

如果有人愿意帮助我,我将代码推送到 github 到 static 分支:

https://github.com/floor-org/floor/tree/static

【问题讨论】:

    标签: rust object-lifetime


    【解决方案1】:

    这里的问题是,为了安全地创建一个装箱的 trait 对象,原始对象不能有任何生命周期参数(static 除外),或者对象本身也需要尊重该生命周期,这是不可能的一般来说。修复它:

    pub fn add<T: MiddlewareHandler + 'static> (&mut self, handler: T) {
        self.handlers.push(box handler);
    }
    

    读起来有点奇怪,但它是说“T 需要实现 MiddlewareHandler 并且它不能包含任何没有 static 生命周期的引用”。这仅适用于static

    【讨论】:

    • 我想我在这个 sn-p 的几乎每个地方都添加了' static,但我显然错过了尝试+ 'staticthere ;-) 但我不明白的一件事是为什么那里不需要:github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67 他们的实现在这方面有何不同?
    • 因为 trait 继承自 Send,而 Send 暗示 'static
    • 该死!我查看了Send 的文档,但它没有响铃,因为我没有在这里产生任何任务,所以它似乎是多余的。也许您可以回答两个额外的问题:pub trait MiddlewareHandler: Clone + Send 有效,但为此“滥用”Send 感觉很奇怪。那我为什么不能用pub trait MiddlewareHandler: Clone + 'static呢?你说Send 暗示'static 但我查看了doc.rust-lang.org/core/kinds/trait.Send.html 的来源并找不到任何提示。我希望在某处看到'static
    • 种类有点奇怪,它们现在是语言内置的(尽管there is an RFC to change that)。我会期望 Clone + 'static 工作,我很遗憾它没有。
    • 好的,那么。如果您真的只是想让您的类型为静态 atm,那么从 send 派生是否正确?我想写惯用的 Rust 并且从 send 派生似乎没有必要考虑到它的描述。你会用目前的 Rust 设计做同样的事情吗?
    【解决方案2】:

    特征对象会擦除内部数据的类型,这意味着仅通过查看 Box&lt;Trait&gt; 特征对象就无法知道它。特别是,数据的任何生命周期也会被删除,因此编译器无法判断特征对象是否/何时包含对无效数据的引用(即某些引用的生命周期已过期),因此 Rust 当前强制要求拥有的特征对象中的任何数据绝不能“过期”。也就是说,其中没有引用(确切地说,任何引用都是永久有效的,即'static)。

    这通过内置的“特征”'static 表达:

    pub fn add<T: 'static + MiddlewareHandler>(...
    

    (这可能会在未来发生变化,拥有的 trait 对象能够受实际生命周期的限制,因此存储非'static 引用将是安全的。)

    【讨论】:

    • 很好的答案!感谢那。我仍然想知道为什么这对他们有用:github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67 我看不出他们的代码与我的代码有何不同。另外,如果我像这样更改代码,我会遇到下一个错误instantiating a type parameter with an incompatible type T, which does not fulfill 'static 所以,这似乎表明我在其他地方可能有错误? :-S
    猜你喜欢
    • 1970-01-01
    • 2011-05-06
    • 2013-01-07
    • 2011-11-04
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多