我正在创建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
我的印象是,特征包含两个指针,一个指向vtable,另一个指向对象数据。因此,包括MyTrait
在内的任何特征的大小都应为2 * pointer_size
。此外,对象数据指针指向大小已知的MyStruct
。显然,我的理解是错误的,但我不知道为什么。这是我的代码:
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
}
}
最佳答案
当您在MyTrait
中将方法声明为fn my_fun(self);
时,这将创建一个通过值而不是通过引用使用self
参数的方法。在Rust中,大多数值都没有隐式克隆(对于那些值,它仅支持逐位直接复制)。
通常,按值传递参数会导致其被移动,此后其旧位置不再有效,并且以某种方式变为无效行为。 (尽管这不会发生是由编译器强制执行的。)
错误并不是说您不能在Box<dyn MyTrait>
的值中包含HashMap
,而是您不能将dyn MyTrait
从&Box<dyn MyTrait>
调用中获得的hm.get
引用中移出。即使在那里有大小类型而不是无大小类型,这仍然是不可能的,因为除非类型为Copy
,否则您不能将值从共享引用的后面移出。 (在这种情况下,它是完全复制而不是移动的。)
最有可能的是,您想使用fn my_fun(&self)
,它通过引用而不是值来接受self参数。
如果要更改函数中的值,则应声明函数fn my_fun(&mut self)
,然后将hm.get
替换为hm.get_mut
,以便您可以对MyStruct
进行可变引用。
如果确实需要通过值而不是引用来获取self参数,则可以编写fn my_fun(self: Box<Self>)
声明self参数是一个装箱的值,然后将hm.get
行更改为hm.remove
。顾名思义,这将使值不再在哈希图中可访问。
关于rust - dyn MyTrait的大小无法在采用self的方法中静态确定。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63766721/