在递归枚举上使用附带移动值错误 [英] Use of collaterally moved value error on a recursive enum
问题描述
我具有用于实现列表的递归 Item
结构:
I have a recursive Item
structure that I am using to implement lists:
#[derive(Debug)]
pub enum Item<T> {
Cons(T, Box<Item<T>>),
Nil,
}
当实现一个在另一个元素之后插入元素的函数时,我发现Rust编译器对我的代码并不满意:
When implementing a function that inserts an element after another one, I found out that the Rust compiler wasn't that happy about my code:
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match *it {
Item::Nil => return it,
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
return Box::new(Item::Cons(a, itm));
}
}
}
我得到的错误是
error[E0382]: use of collaterally moved value: `(it as Item::Cons).1`
--> src/main.rs:12:23
|
12 | Item::Cons(a, b) => {
| - ^ value used here after move
| |
| value moved here
|
= note: move occurs because the value has type `T`, which does not implement the `Copy` trait
建议另一个类似的问题展开阶段分两步进行,但不能在这里使用,因为我们需要直接展开两个字段 Cons(..)
的项,而不是诸如<$ c $的嵌套项c> Option< Box< Whatever>> 可以应用两阶段技巧。我尝试过的示例:
Another similar question suggested to do the unwrapping phase in two steps but it cannot be used here because we need to directly unwrap a two-fields Cons(..)
item and not nested items like Option<Box<Whatever>>
where the two-phase trick can be applied. Example of what I tried:
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match *it {
Item::Nil => return it,
Item::Cons(..) => {
let Item::Cons(a, b) = *it;
let itm = Box::new(Item::Cons(val, b));
return Box::new(Item::Cons(a, itm));
}
}
}
但我收到另一个错误:
But I get another error:
error[E0005]: refutable pattern in local binding: `Nil` not covered
--> src/main.rs:13:17
|
13 | let Item::Cons(a, b) = *it;
| ^^^^^^^^^^^^^^^^ pattern `Nil` not covered
尽管我在这里非常确定,但由于我们之前已经匹配了缺点
,所以在这里还是很详尽的。
Though I am pretty sure here that this is exhaustive at this point because we matched a Cons
before.
推荐答案
您可能正在遭受问题16223 (另请参见 22205 ,该书的复制较为紧密),尽管今天不是词汇一辈子都不能解决这个问题。这似乎排除了通过 Box
破坏多个事物的可能性。
You may be suffering from issue 16223 (see also 22205 which has a closer reproduction), although today's non-lexical lifetimes don't solve this problem. This seems to preclude destructuring multiple things through a Box
.
这是解决它的一种方法,尽管它不是最的高效方法,因为它不必要地进行了重新分配:
Here's one way to work around it, although it's not the most efficient way as it deallocates and reallocates unnecessarily:
#[derive(Debug)]
pub enum Item<T> {
Cons(T, Box<Item<T>>),
Nil,
}
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match { *it } {
Item::Nil => Box::new(Item::Nil),
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
Box::new(Item::Cons(a, itm))
}
}
}
fn main() {}
更冗长的方式将值从 Box
,操纵那个,然后将操纵后的值放回 Box
中。这应该减少分配的数量:
A more verbose way pulls the value out of the Box
, manipulates that, and then puts the manipulated value back into the Box
. This should have a reduced amount of allocations:
use std::mem;
pub fn add_after<T>(mut item: Box<Item<T>>, val: T) -> Box<Item<T>> {
let unboxed_value = mem::replace(&mut *item, Item::Nil);
match unboxed_value {
Item::Nil => item,
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
*item = Item::Cons(a, itm);
item
}
}
}
请参阅还:
- Collaterally moved error when deconstructing a Box of pairs
这篇关于在递归枚举上使用附带移动值错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!