先来看看Java的继承和重写是怎么做的吧!
##Java继承的示例
class Person{
private String name;
public void setName(String name){
this.name = name;
}
public void say() {
System.out.println("我是一个人,名字叫" + this.name);
}
}
// 学生继承人的属性的方法
// 添加了自己的属性和方法
class Student extends Person{
private String role;
public void setRole(String role) {
this.role = role;
}
}
public class Demo01{
public static void main(String args[]){
Student stu = new Student();
stu.setName("曾赛");
stu.setRole("班长");
stu.say();
}
}
输出:
我是一个人,名字叫曾赛
抛开面向对象的思想,从语法的角度来分析,可以看到:我们通过继承在Student这个类型上调用到了Person这个类型中的方法。从而复用了Person类的代码。
但有的时候我们需要重写父类的方法,一个学生的介绍可能不同于其它人。这就需要重写父类方法:
class Person{
private String name;
public void setName(String name){
this.name = name;
}
public void say() {
System.out.println("我是一个人,名字叫" + this.name);
}
}
// 学生继承人的属性的方法
// 添加了自己的属性和方法
class Student extends Person{
private String role;
public void setRole(String role) {
this.role = role;
}
public void say() {
System.out.println("我是一个学生,名字叫" + this.name +",担任" + this.role);
}
}
public class Demo01{
public static void main(String args[]){
Student stu = new Student();
stu.setName("曾赛");
stu.setRole("班长");
stu.say();
}
}
输出:
我是一个学生,名字叫曾赛,担任班长
##Rust中用Deref和DerefMut特性实现Java的继承
struct Person {
name: String,
}
impl Person {
fn setName(&mut self, name: &str) {
self.name = name.to_string();
}
fn say(&self) {
println!("我是一个人,名字叫{}", self.name);
}
}
struct Student {
p: Person,
role: String,
}
impl Student {
fn new() -> Student {
Student {
p: Person {
name:"没有名字".to_string()
},
role:"普通学生".to_string()
}
}
fn setRole(&mut self, role: &str) {
self.role = role.into()
}
}
fn main() {
let mut stu = Student::new();
stu.setRole("班长");
stu.say();
}
编译出错:
obj.rs:38:9: 38:14 error: no method named `say` found for type `Student` in the current scope
obj.rs:38 stu.say();
^~~~~
error: aborting due to previous error
说明通过简单的包含不会达到继承的效果。要能访问到Person中的方法,我们还需要为Student实现一个特性:
use std::ops::Deref;
impl Deref for Student {
type Target = Person;
fn deref<'a>(&'a self) -> &'a Person {
&self.p
}
}
编译输出:
我是一个人,名字叫没有名字
可以看出,通过实现Deref特性,我们可以模拟继承,在Student类型的对象上调用Person类型的方法。
看到上面我们的输出,Student没有名字,这怎么可以,我们来把名字给加上,很简单,修改main函数如下:
fn main() {
let mut stu = Student::new();
stu.setName("曾赛");
stu.setRole("班长");
stu.say();
}
编译输出:
obj.rs:47:5: 47:8 error: cannot borrow immutable borrowed content as mutable
obj.rs:47 stu.setName("曾赛");
^~~
error: aborting due to previous error
实现了Deref特性后,我们确实可以访问到Person的方法了,但是不能修改他的属性!为什么?我的stu对象已经用mut修饰了,成员p应该是可以修改的呀!
原因很简单,通过这种方法来访问Person是利用了Rust中叫Auto-Deref的规则来实现:在stu调用一个Student类没有提供的方法setName,编译器会自动调用stu的deref方法,并在返回的类型上继续寻找该方法,直到找到方法或者是返回的类型不能被deref。
之所以会出这个错误,是因为stu的deref方法返回的&'a Person类型,是一个不可变的引用。要让main函数可以工作,我们就还需要实现另一个特性:
use std::ops::DerefMut;
impl DerefMut for Student {
fn deref_mut<'a>(&'a mut self) -> &'a mut Person {
&mut self.p
}
}
编译输出:
我是一个人,名字叫曾赛
Oh Yeah!成功!
通过Deref与DerefMut特性,我们实现了Java中的继承。
##Rust重写Person类型的方法
这个很简单,根据上面的Auto-Deref规则描述,只要在Student中定义一个签名相同的方法就可以了。
impl Student {
......
fn say(&self) {
println!("我是一个学生,名字叫{},担任{}", self.name, self.role);
}
编译输出:
我是一个学生,名字叫曾赛,担任班长
Rust 是一门很棒的语言,你值得拥有!