为什么在取消引用的特征对象或切片上调用方法会编译?
Why does calling a method on a dereferenced trait object or slice compile?
给定以下代码:
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"?
从第一段代码产生的MIR判断,(*f).filter()
等价于f.filter()
;编译器似乎知道,由于 filter
是 &self
上的一个方法,取消引用它没有任何作用,因此被完全省略。
然而,第二种情况不同,因为取消引用切片会引入 bounds-checking 代码。在我看来,编译器还应该能够判断此操作(取消引用)不会引入任何有意义的更改(and/or 不会出现 out-of-bounds 错误)并将其视为常规切片索引,但这背后可能有一些原因。
解除对特征对象的引用没有问题。事实上,它必须在某个时候被取消引用,否则它会毫无用处。
let k1 = (*f);
失败不是因为取消引用,而是因为您试图将原始特征对象放在堆栈上(这是局部变量所在的位置)。堆栈上的值必须具有在编译时已知的大小,特征对象不是这种情况,因为任何类型都可以实现该特征。
这是一个示例,其中具有不同大小的结构实现了特征:
trait Function {
fn filter (&self);
}
#[derive(Debug, Copy, Clone)]
struct Kidney {}
impl Function for Kidney {
fn filter (&self) {
println!("filtered");
}
}
#[derive(Debug, Copy, Clone)]
struct Liver {
size: f32
}
impl Function for Liver {
fn filter (&self) {
println!("filtered too!");
}
}
fn main() {
let k = Kidney {};
let l = Liver {size: 1.0};
let f: &Function;
if true {
f = &k;
} else {
f = &l;
}
// Now what is the size of *f - Kidney (0 bytes) or Liver (4 bytes)?
}
(*f).filter();
起作用是因为暂时取消引用的对象没有放在堆栈上。其实这和f.filter()
是一样的。 Rust 会根据需要自动应用尽可能多的解引用以获取实际对象。这已记录在案 in the book。
第二种情况发生的是Vec
implements Deref
到切片,所以它免费获得切片实现的所有方法。 *v
给你一个取消引用的切片,你将它分配给一个切片。这是一个明显的类型错误。
给定以下代码:
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"?
从第一段代码产生的MIR判断,(*f).filter()
等价于f.filter()
;编译器似乎知道,由于 filter
是 &self
上的一个方法,取消引用它没有任何作用,因此被完全省略。
然而,第二种情况不同,因为取消引用切片会引入 bounds-checking 代码。在我看来,编译器还应该能够判断此操作(取消引用)不会引入任何有意义的更改(and/or 不会出现 out-of-bounds 错误)并将其视为常规切片索引,但这背后可能有一些原因。
解除对特征对象的引用没有问题。事实上,它必须在某个时候被取消引用,否则它会毫无用处。
let k1 = (*f);
失败不是因为取消引用,而是因为您试图将原始特征对象放在堆栈上(这是局部变量所在的位置)。堆栈上的值必须具有在编译时已知的大小,特征对象不是这种情况,因为任何类型都可以实现该特征。
这是一个示例,其中具有不同大小的结构实现了特征:
trait Function {
fn filter (&self);
}
#[derive(Debug, Copy, Clone)]
struct Kidney {}
impl Function for Kidney {
fn filter (&self) {
println!("filtered");
}
}
#[derive(Debug, Copy, Clone)]
struct Liver {
size: f32
}
impl Function for Liver {
fn filter (&self) {
println!("filtered too!");
}
}
fn main() {
let k = Kidney {};
let l = Liver {size: 1.0};
let f: &Function;
if true {
f = &k;
} else {
f = &l;
}
// Now what is the size of *f - Kidney (0 bytes) or Liver (4 bytes)?
}
(*f).filter();
起作用是因为暂时取消引用的对象没有放在堆栈上。其实这和f.filter()
是一样的。 Rust 会根据需要自动应用尽可能多的解引用以获取实际对象。这已记录在案 in the book。
第二种情况发生的是Vec
implements Deref
到切片,所以它免费获得切片实现的所有方法。 *v
给你一个取消引用的切片,你将它分配给一个切片。这是一个明显的类型错误。