如何防止移入功能的 impl Trait 在借用时被删除?
How do I prevent impl Trait moved into function from being dropped while still borrowed?
我想定义一个 trait Holder
可以通过 items
方法迭代一些。我不想从这个方法 return 一个特征对象,因为如果可能的话我想坚持使用静态分派和堆栈分配。我的系统工作正常,但在某种令人惊讶的情况下失败了。
代码如下:
pub trait Holder<'a, N: 'a> {
type Items: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::Items;
}
struct Impl<N> {
items: Vec<N>
}
impl<'a, N: 'a> Holder<'a, N> for Impl<N> {
type Items = std::slice::Iter<'a, N>;
fn items(&'a self) -> Self::Items {
self.items.iter()
}
}
fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
// COMPILE ERROR
for item in holder.items() {
}
}
这是错误:
error[E0309]: the parameter type `impl Holder<'a, N>` may not live long enough
--> src/graph/test.rs:20:17
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
| ------------------ help: consider adding an explicit lifetime bound...: `impl Holder<'a, N> + 'a`
20 | for item in holder.items() {
| ^^^^^^
|
note: ...so that the type `impl Holder<'a, N>` is not borrowed for too long
--> src/graph/test.rs:20:17
|
20 | for item in holder.items() {
| ^^^^^^
error[E0309]: the parameter type `impl Holder<'a, N>` may not live long enough
--> src/graph/test.rs:20:24
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
| ------------------ help: consider adding an explicit lifetime bound...: `impl Holder<'a, N> + 'a`
20 | for item in holder.items() {
| ^^^^^
|
note: ...so that the reference type `&'a impl Holder<'a, N>` does not outlive the data it points at
--> src/graph/test.rs:20:24
|
20 | for item in holder.items() {
| ^^^^^
error: aborting due to 2 previous errors; 4 warnings emitted
For more information about this error, try `rustc --explain E0309`.
我听从了编译器的建议并添加了显式生命周期:
pub trait Holder<'a, N: 'a> {
type Items: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::Items;
}
struct Impl<N> {
items: Vec<N>
}
impl<'a, N: 'a> Holder<'a, N> for Impl<N> {
type Items = std::slice::Iter<'a, N>;
fn items(&'a self) -> Self::Items {
self.items.iter()
}
}
fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N> + 'a) {
for item in holder.items() {
}
}
给出错误:
error[E0597]: `holder` does not live long enough
--> src/graph/test.rs:20:17
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N> + 'a) {
| -- lifetime `'a` defined here
20 | for item in holder.items() {
| ^^^^^^--------
| |
| borrowed value does not live long enough
| argument requires that `holder` is borrowed for `'a`
...
23 | }
| - `holder` dropped here while still borrowed
我已经看到 this question 和其他几个与此问题无关的问题,但无法理解如何继续前进。
除了 return 从 Hoder#items
获取特征对象外,我还有哪些选择可以使 use_hodler
中的循环正常工作?
这实际上非常困难 - 生命周期和关联类型似乎是 Rust 中那些(尚未)得到很好支持的奇怪极端情况之一。如果我说我正确理解了错误的原因,那我就是在撒谎,但是我已经设法让这个工作 对于这个特定的例子 使用 Higher Ranked Trait Bounds.
您只需更改一行:
fn use_holder<N>(holder: impl for<'a> Holder<'a, N>) {
请注意,生命周期参数已移至 for<'a>
。这意味着 holder
参数为每个可能的生命周期 'a
实现 Holder<'a, N>
,而不是为至少与函数一样长的特定 'a
实现。
你需要使用 for<'a> ...
大多数你使用这个特性的地方,所以它很快就会变得混乱。并且更高等级的特征边界不是一个常用的特性:它非常小众并且在最常见的情况下被忽略了,所以它不会帮助提高易读性或可维护性。
我建议您更改架构,尽可能避免这种构造。
我想定义一个 trait Holder
可以通过 items
方法迭代一些。我不想从这个方法 return 一个特征对象,因为如果可能的话我想坚持使用静态分派和堆栈分配。我的系统工作正常,但在某种令人惊讶的情况下失败了。
代码如下:
pub trait Holder<'a, N: 'a> {
type Items: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::Items;
}
struct Impl<N> {
items: Vec<N>
}
impl<'a, N: 'a> Holder<'a, N> for Impl<N> {
type Items = std::slice::Iter<'a, N>;
fn items(&'a self) -> Self::Items {
self.items.iter()
}
}
fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
// COMPILE ERROR
for item in holder.items() {
}
}
这是错误:
error[E0309]: the parameter type `impl Holder<'a, N>` may not live long enough
--> src/graph/test.rs:20:17
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
| ------------------ help: consider adding an explicit lifetime bound...: `impl Holder<'a, N> + 'a`
20 | for item in holder.items() {
| ^^^^^^
|
note: ...so that the type `impl Holder<'a, N>` is not borrowed for too long
--> src/graph/test.rs:20:17
|
20 | for item in holder.items() {
| ^^^^^^
error[E0309]: the parameter type `impl Holder<'a, N>` may not live long enough
--> src/graph/test.rs:20:24
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
| ------------------ help: consider adding an explicit lifetime bound...: `impl Holder<'a, N> + 'a`
20 | for item in holder.items() {
| ^^^^^
|
note: ...so that the reference type `&'a impl Holder<'a, N>` does not outlive the data it points at
--> src/graph/test.rs:20:24
|
20 | for item in holder.items() {
| ^^^^^
error: aborting due to 2 previous errors; 4 warnings emitted
For more information about this error, try `rustc --explain E0309`.
我听从了编译器的建议并添加了显式生命周期:
pub trait Holder<'a, N: 'a> {
type Items: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::Items;
}
struct Impl<N> {
items: Vec<N>
}
impl<'a, N: 'a> Holder<'a, N> for Impl<N> {
type Items = std::slice::Iter<'a, N>;
fn items(&'a self) -> Self::Items {
self.items.iter()
}
}
fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N> + 'a) {
for item in holder.items() {
}
}
给出错误:
error[E0597]: `holder` does not live long enough
--> src/graph/test.rs:20:17
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N> + 'a) {
| -- lifetime `'a` defined here
20 | for item in holder.items() {
| ^^^^^^--------
| |
| borrowed value does not live long enough
| argument requires that `holder` is borrowed for `'a`
...
23 | }
| - `holder` dropped here while still borrowed
我已经看到 this question 和其他几个与此问题无关的问题,但无法理解如何继续前进。
除了 return 从 Hoder#items
获取特征对象外,我还有哪些选择可以使 use_hodler
中的循环正常工作?
这实际上非常困难 - 生命周期和关联类型似乎是 Rust 中那些(尚未)得到很好支持的奇怪极端情况之一。如果我说我正确理解了错误的原因,那我就是在撒谎,但是我已经设法让这个工作 对于这个特定的例子 使用 Higher Ranked Trait Bounds.
您只需更改一行:
fn use_holder<N>(holder: impl for<'a> Holder<'a, N>) {
请注意,生命周期参数已移至 for<'a>
。这意味着 holder
参数为每个可能的生命周期 'a
实现 Holder<'a, N>
,而不是为至少与函数一样长的特定 'a
实现。
你需要使用 for<'a> ...
大多数你使用这个特性的地方,所以它很快就会变得混乱。并且更高等级的特征边界不是一个常用的特性:它非常小众并且在最常见的情况下被忽略了,所以它不会帮助提高易读性或可维护性。
我建议您更改架构,尽可能避免这种构造。