简体   繁体   English

如何限制关联类型接受任何引用生命周期?

[英]How can I constrain an associated type to accept any reference lifetime?

I have a simple trait which has a function which accepts an associate type.我有一个简单的特征,它有一个接受关联类型的函数。

pub trait Pipe {
    type Item;
    
    fn push(&mut self, value: Self::Item);
}

Now I want to do something with a Pipe that accepts references rather than owned values.现在我想用一个接受引用而不是拥有值的Pipe做一些事情。

pub fn do_something_ref<T>(trait_inst: T)
where
    T: Pipe<Item = &usize>
{
    let val: usize = 5;
    trait_inst.push(&val);
}

The references will not live longer than the caller context lifetime.引用的存活时间不会超过调用者上下文的生命周期。 Maybe the Pipe clones the value.也许 Pipe 克隆了这个值。 Maybe it will just println it.也许它只会打印它。 But it will not be allowed to store it since that would violate the caller context lifetime.但是不允许存储它,因为这会违反调用者上下文生命周期。

However the code above give an error: error[E0637]: `&` without an explicit lifetime name cannot be used here .然而,上面的代码给出了一个错误: error[E0637]: `&` without an explicit lifetime name cannot be used here

Playground Link 游乐场链接

How can I make this work?我怎样才能使这项工作?

Here's my attempt.这是我的尝试。

So, it seems that higher ranked trait bounds (HRTB) are useful here.因此,似乎更高等级的特征边界 (HRTB)在这里很有用。 If I can say " P: Pipe<Item = &'a> for all possible 'a " then that would mean the Pipe would accept very short-lived references.如果我可以说“ P: Pipe<Item = &'a> for all possible 'a ” 那么这意味着 Pipe 将接受非常短暂的引用。

pub fn do_something_ref<T>(trait_inst: T)
where
    for <'a> T: Pipe<Item = &'a usize>
{
    let val: usize = 5;
    trait_inst.push(&val);
}

I think this should work, but it doesn't compile either: error[E0582]: binding for associated type `Item` references lifetime `'a`, which does not appear in the trait input types .我认为这应该有效,但它也不能编译: error[E0582]: binding for associated type `Item` references lifetime `'a`, which does not appear in the trait input types

Playground Link 游乐场链接

Is that error a bug?该错误是错误吗?

Could be https://github.com/rust-lang/rust/issues/49601 ?可以是https://github.com/rust-lang/rust/issues/49601吗?

So it seems this error only happens because the 'a isn't in a spot that the compiler recognizes as valid for for<'a> .所以这个错误似乎只是因为'a不在编译器认为对for<'a>有效的地方。 So I tried to find some workaround by adding an unused lifetime parameter or helper traits, and although I found some solutions which initially compiled , none actually work when you try to use them.所以我试图通过添加一个未使用的生命周期参数或辅助特征来找到一些解决方法,虽然我找到了一些最初编译的解决方案,但当你尝试使用它们时,没有一个真正起作用。

How can I get this to work how I want?我怎样才能让它按照我想要的方式工作? Thanks!谢谢!


Old discussion on internals: "Opposite of &'static"关于内部的旧讨论:“与 &'static 相对”

If not holding on to the reference is a property of push() , you can fix the issue by modifying the trait (the question is not clear on whether that's allowed):如果不保留引用是push()的属性,您可以通过修改特征来解决问题(问题不清楚是否允许):

pub trait Pipe<'a> {
    type Item;

    fn push(&mut self, value: Self::Item);
}

pub fn do_something_ref<T>(mut trait_inst: T)
where
    T: for<'a> Pipe<'a, Item = &'a usize>,
{
    let val: usize = 5;
    trait_inst.push(&val);
}

...and it can be implemented ( playground ). ...它可以实现( 操场)。

Without modifying the trait there would, as the other answer puts it, be nothing stopping push() from holding onto the value.如果不修改特征,就像另一个答案所说的那样,没有什么可以阻止push()保留该值。 (A similar concern prevents streaming iterators from working - except you cannot "fix" iterators because the fix would stop regular iterators from working.) (类似的问题会阻止流迭代器工作——除非你不能“修复”迭代器,因为修复会阻止常规迭代器工作。)

You can do that adding a generic lifetime to your function:您可以这样做,为您的函数添加通用生命周期:

pub fn do_something_ref<'i, T>(mut trait_inst: T)
where
    T: Pipe<Item = &'i usize>
{
    let val: usize = 5;
    trait_inst.push(&val);
}

However, this will fail with the error message:但是,这将失败并显示错误消息:

error[E0597]: `val` does not live long enough
  --> src/lib.rs:12:21
   |
7  | pub fn do_something_ref<'i, T>(mut trait_inst: T)
   |                         -- lifetime `'i` defined here
...
12 |     trait_inst.push(&val);
   |     ----------------^^^^-
   |     |               |
   |     |               borrowed value does not live long enough
   |     argument requires that `val` is borrowed for `'i`
13 | }
   | - `val` dropped here while still borrowed

Which is expected.这是预期的。 What prevents your Pipe implementation to store that reference and use it after returning from do_something_ref , causing undefined behaviour?是什么阻止您的Pipe实现存储该引用并在从do_something_ref返回后使用它,从而导致未定义的行为? Rust prevents you from doing that by requiring that the 'i lifetime comes from outside this function. Rust 通过要求'i生命周期来自这个函数之外来阻止你这样做。 Something like this does work:像这样的东西确实有效:

pub fn do_something_ref<'i, T>(mut trait_inst: T, x: &'i usize)
where
    T: Pipe<Item = &'i usize>
{
    trait_inst.push(&x);
}

Another option is to ... give up on generics and just create two traits.另一种选择是……放弃泛型,只创建两个特征。

This is effectively trentcl's comment "lift the reference so the lifetime becomes part of the signature of push" , and is what I ended up doing.这实际上是trentcl 的评论“提升引用,使生命周期成为推送签名的一部分” ,这就是我最终做的。

pub trait Pipe {
    type Item;
    
    fn push(&mut self, value: Self::Item);
}
pub trait RefPipe {
    type Item;
    
    fn push(&mut self, value: &Self::Item); // Reference here
}

(And RefPipe can be treated as Pipe s and received owned values, if you want) (如果您愿意,可以将RefPipe视为Pipe并接收拥有的值)

impl<P: RefPipe> Pipe for P {
    type Item = P::Item;

    fn push(&mut self, item: Self::Item) -> Result<(), &'static str> {
        Pipe::push(self, &item)
    }
}

暂无
暂无

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

相关问题 如何将结构的生命周期限制为“父”结构的生命周期? - How can I constrain the lifetime of a struct to that of a 'parent' struct? 如何指定一个带引用的闭包,并返回实现与引用具有相同生命周期的特征的任何类型? - How do I specify a closure that takes a reference and returns any type implementing a trait with the same lifetime as the reference? 如何在关联类型中指定生命周期参数? - How do I specify lifetime parameters in an associated type? 如何使用生命周期参数指定关联类型? - How do I specify an associated type with a lifetime parameter? 如何在具有生命周期限制的类型上命名关联类型? - How to name an associated type on a type with a lifetime bound? 如何为将成为闭包参数的关联类型指定生命周期? - How to specify lifetime for associated type that will be a closure argument? 如何为包含对具有生命周期参数的类型的引用的类型声明生命周期参数? - How do I declare the lifetime parameters for a type which contains a reference to a type with a lifetime parameter? 将内部引用传递给通用闭包时的关联类型生存期 - Associated type lifetime when passing internal reference to a generic closure 如何将任何类型的引用转换为对长度为 1 的数组的引用? - How can I convert a reference to any type to a reference to an array of length 1? 关联类型的生命周期 - self lifetime on associated type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM