pub fn object_safety()
Expand description
§对象安全
§对象安全
为什么必须是对象安全呢?
trait对象,在运行时已经擦除了类型信息,要通过虚表调用相应的方法。不像静态分发那样,trait对象不是为每个类型都实现trait的方法,而是只实现一个副本(自动为其实现自身),结合虚函数去调用。
现在想一个问题: 假如那个类型没有实现这个方法怎么办? 实际上,会有很多种情况下,会出现这个问题。运行时确定的类型和方法应该合法的,保证trait对象在运行时可以安全地调用相关的方法。
比如trait里有泛型函数。这就搞的很复杂了,可能运行时无法确定该调用哪个函数。反正是各种情况吧。所以,为了避免出现这种问题,官方引入了对象安全的概念。 实际上就是引入了一系列的规则,也就是上面列出的那些。编译器根据这些规则,在编译期判断一个你写的trait对象,是不是合法的。
比如:trait对象其实在内部维护两个表:safe_vtable和nonself_vtable,标记有where Self: Sized的会被归类到nonself_vtable,也就是说,不会被trait对象调用。 这样的话,方法标记有where Self: Sized的trait对象自然是安全的,因为这表示 这个方法 只能为 Self: Sized 都类型实现,是有条件的,所以在运行时有可能存在无效(万一有不是Sized的类型调用,就没有该方法)调用。
如果是合法的,则代表了,这个trait对象在运行时调用方法应该是没问题的。 不会出现没有实现,或者不知道该调用哪个的情况。 这就是对象安全的概念。它和内存安全并无直接关系。 所以,对象安全的本质就是为了让trait对象可以安全地调用相应的方法。
如果没有Sized的限定,那么就会很容易写出无用的类型。比如 Box,它用做trait对象即便会编译,但是不能用它做任何事情(后面有演示代码)。 对于更复杂的trait,往往就没有这么明显了,只有在做了大量繁重的工作之后可能会突然发现某个trait对象无法正常调用方法。 所以,为trait增加Sized限定,然后编译器自动为该trait实现自身,就可以在编译期准确排除无效的trait对象。 这就是对象安全。需要注意的是,对象安全和内存安全并无直接的关联,它只是保证trait对象在运行时可以安全准确地调用相关的方法。
trait StarkFamily {
fn last_name(&self) -> &'static str;
fn totem(&self) -> &'static str;
}
trait TullyFamily {
fn territory(&self) -> &'static str;
}
trait Children {
fn new(first_name: &'static str) -> Self where Self: Sized;
fn first_name(&self) -> &'static str;
}
impl StarkFamily for Children {
fn last_name(&self) -> &'static str{
"Stark"
}
fn totem(&self) -> &'static str{
"Wolf"
}
}
impl TullyFamily for Children {
fn territory(&self) -> &'static str{
"Riverrun City"
}
}
struct People{
first_name: &'static str
}
impl Children for People {
fn new(first_name: &'static str) -> Self where Self: Sized{
println!("hello : {} Stark ", first_name);
People{first_name: first_name}
}
fn first_name(&self) -> &'static str{
self.first_name
}
}
fn full_name(person: Box<dyn Children>) {
println!(" --- Winter is coming, the lone {:?} dies, the pack lives ---", person.totem());
let full = format!("{} {}", person.first_name(), person.last_name() );
println!("I'm {:?}", full );
println!("My Mother come from {:?}", person.territory());
}
fn main() {
let sansa = People::new("Sansa");
let aray = People::new("Aray");
let starks: Box<dyn Children> = Box::new(sansa);
full_name(starks);
let starks: Box<dyn Children> = Box::new(aray);
full_name(starks);
}
对象安全规则 Rust 源码:https://github.com/rust-lang/rust/blob/941343e0871dd04ea774e8cee7755461b144ef29/compiler/rustc_middle/src/traits/mod.rs#L643