冗长的冗余分配皮棉

时间:2020-10-12 03:11:01

标签: rust static-analysis rust-clippy

所以我有这个特征和一个实现它的结构:

trait Trait {
    fn foo(&self) -> u64;
}

/// No Copy trait supported because it's expensive
struct Expensive {
    id: u64,
}

impl Trait for Expensive {
    fn foo(&self) -> u64 {
        self.id
    }
}

我还有一个希望成为全球性的结构,其中包含以下特征:

struct Cheap {
    pub item: Box<dyn Trait>,
}

thread_local! {
    static CHEAP: Cheap = Cheap {
        item: Box::new(Expensive {
            id: 4
        })
    }
}

fn trait_item() -> Box<dyn Trait> {
    CHEAP.with(|c| c.item)
}

这失败是因为

error[E0507]: cannot move out of `c.item` which is behind a shared reference
  --> src/main.rs:35:20
   |
35 |     CHEAP.with(|c| c.item)
   |                    ^^^^^^ move occurs because `c.item` has type `std::boxed::Box<dyn Trait>`, which does not implement the `Copy` trait

总是在.with(...)部分内进行处理实际上是不可行的,因为Trait中包含的某些函数不在乎它来自何处。所以我尝试返回对它的引用:

fn trait_item<'a>() -> &'a Box<dyn Trait> {
    CHEAP.with(|c| &c.item)
}

这也失败了,因为我无法在with之外发送参考:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:33:20
   |
33 |     CHEAP.with(|c| &c.item)
   |                    ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 33:16...
  --> src/main.rs:33:16
   |
33 |     CHEAP.with(|c| &c.item)
   |                ^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:33:20
   |
33 |     CHEAP.with(|c| &c.item)
   |                    ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 32:15...
  --> src/main.rs:32:15
   |
32 | fn trait_item<'a>() -> &'a Box<dyn Trait> {
   |               ^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:33:5
   |
33 |     CHEAP.with(|c| &c.item)
   |     ^^^^^^^^^^^^^^^^^^^^^^^

因此,我将整个内容包装在Rc中,如下所示:

struct Cheap {
    pub item: Rc<Box<dyn Trait>>,
}

thread_local! {
    static CHEAP: Cheap = Cheap {
        item: Rc::new(Box::new(Expensive {
            id: 4
        }))
    }
}

fn trait_item() -> Rc<Box<dyn Trait>> {
    CHEAP.with(|c| c.item.clone())
}

但是现在clippy抱怨:

warning: usage of `Rc<Box<T>>`
  --> src/main.rs:41:15
   |
41 |     pub item: Rc<Box<dyn Trait>>,
   |               ^^^^^^^^^^^^^^^^^^ help: try: `Box<dyn Trait>`
   |
   = note: `#[warn(clippy::redundant_allocation)]` on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation

warning: usage of `Rc<Box<T>>`
  --> src/main.rs:53:20
   |
53 | fn trait_item() -> Rc<Box<dyn Trait>> {
   |                    ^^^^^^^^^^^^^^^^^^ help: try: `Box<dyn Trait>`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation

warning: 2 warnings emitted

我错过了什么吗,还是实际上无法执行clippy的建议?

Rust playground | Relevant Clippy page

1 个答案:

答案 0 :(得分:2)

由于Rc也是指针,因此也可以将特征对象包装在Rc中。

因此,如果您有Rc<Box<T>>,则有两个分配:一个分配给T,另一个分配给Box(另一个指针,现在在堆上)。而是使用Rc<dyn MyTrait>仅分配一次。