dyn MyTrait 的大小无法在采用 self 的方法中静态确定?

rob*_*udd 6 rust

我正在创建一个HashMap<u64, Box<dyn MyTrait>>. 我可以创建HashMap并插入一个实现 的结构MyTrait,但是当我检索MyTrait并尝试使用它时,编译器向我抱怨:

error[E0161]: cannot move a value of type dyn MyTrait: the size of dyn MyTrait cannot be statically determined
Run Code Online (Sandbox Code Playgroud)

我的印象是,一个特征由两个指针组成,一个指向 vtable,一个指向对象数据。所以任何特征的大小,包括MyTrait,都应该是2 * pointer_size。此外,对象数据指针指向MyStruct大小已知的 a 。显然我的理解是错误的,但我不明白为什么。

这是我的代码:

use std::collections::HashMap;

fn main() {
  let mut hm: HashMap<u64, Box<dyn MyTrait>> = HashMap::new();
  hm.insert(0, Box::new(MyStruct{num: 0}));
  match hm.get(&(0 as u64)) {
    Some(r) => {
      r.my_fun();
      }
    None => { println!("not found");}
  }
}

pub trait MyTrait {
  fn my_fun(self);
}

struct MyStruct {
  num: u64,
}

impl MyTrait for MyStruct {
  fn my_fun(self) {
    println!("num is {}", self.num);
    return
  }
}
Run Code Online (Sandbox Code Playgroud)

Lym*_*sia 8

MyTrait当您在as中声明该方法时,这将创建一个按而不是引用获取参数的fn my_fun(self);方法。在 Rust 中,大多数值都没有隐式克隆(对于那些有隐式克隆的值,它只支持直接的逐位复制)。self

一般来说,按值传递参数会导致它被移动,之后它的旧位置不再有效,并且以某种方式访问​​成为无效行为。(尽管编译器强制不会发生这种情况。)

该错误并不是说您不能Box<dyn MyTrait>在 a 的值中包含 a HashMap,而是说您不能将 a 移出dyn MyTrait从调用&Box<dyn MyTrait>中获得的引用hm.get。即使您有一个已调整大小的类型而不是未调整大小的类型,这仍然是不可能的,因为您无法将值从共享引用后面移出,除非类型是Copy。(在这种情况下,它只是被复制而不是被移动。)

最有可能的是,您想改用fn my_fun(&self)它,它通过引用而不是值来获取 self 参数。

如果您想改变函数中的值,您应该声明该函数fn my_fun(&mut self)并将 替换为hm.gethm.get_mut以便您拥有对MyStruct.

如果您确实需要通过值而不是引用来获取 self 参数,您可以编写fn my_fun(self: Box<Self>)声明 self 参数是一个装箱值,然后将该行更改hm.gethm.remove。顾名思义,这使得哈希映射中的值无法再访问。