给出以下代码:
trait Function {
fn filter (&self);
}
#[derive(Debug, Copy, Clone)]
struct Kidney {}
impl Function for Kidney {
fn filter (&self) {
println!("filtered");
}
}
fn main() {
let k = Kidney {};
let f: &Function = &k;
//let k1 = (*f); //--> This gives a "size not satisfied" error
(*f).filter(); //--> Works; what exactly happens here?
}
我不确定它为什么编译 . 我期待最后一个声明失败 . 我想我在学习Rust时忽略了一些基础知识,因为我无法理解为什么解引用特征(生活在指针后面)应该编译 .
这个问题是否类似于以下情况?
let v = vec![1, 2, 3, 4];
//let s: &[i32] = *v;
println!("{}", (*v)[0]);
*v
给出了一个切片,但是切片是未分级的,所以我再也不清楚它是如何编译的 . 如果我取消注释我得到的第二个陈述
| let s:&[i32]= *v;
| ^^
| |
| expected &[i32], found slice
| help: consider borrowing here: `&*v`
|
= note: expected type `&[i32]`
found type `[{integer}]`
expected type &[i32]
是指"expected a reference of slice"?
2 回答
取消引用特征对象是没有问题的 . 事实上,它必须在某个时候被取消引用,否则它将毫无用处 .
let k1 = (*f);
失败不是因为解除引用,而是因为你试图将原始特征对象放在堆栈上(这是局部变量存在的地方) . 堆栈上的值必须具有编译时已知的大小,而特征对象不是这种情况,因为任何类型都可以实现特征 .下面是一个示例,其中具有不同大小的结构实现了特征:
(*f).filter();
有效,因为暂时取消引用的对象没有放在堆栈上 . 实际上,这与f.filter()
相同 . Rust会自动应用所需数量的解引用来获取实际对象 . 记录in the book .在第二种情况下发生的是切片的Vec implements Deref,因此它可以免费获得为切片实现的所有方法 .
*v
为您提供了一个解除引用的切片,您可以将其指定给切片 . 这是一个明显的类型错误 .根据第一段代码生成的MIR判断,
(*f).filter()
相当于f.filter()
;似乎编译器知道由于filter
是&self
上的一个方法,因此取消引用它不起任何作用,并且完全省略 .但是,第二种情况不同,因为解引用切片会引入边界检查代码 . 在我看来,编译器还应该能够告诉该操作(解除引用)不会引入任何有意义的更改(和/或不会出现越界错误)并将其视为常规切片索引,但这背后可能有一些原因 .