在递归枚举上使用附带移动值错误 [英] Use of collaterally moved value error on a recursive enum

查看:67
本文介绍了在递归枚举上使用附带移动值错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有用于实现列表的递归 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆