[英]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
。
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
。
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.