Rust用组合实现java中的继承重写

原创
2015/08/22 12:55
阅读数 3.1K

先来看看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 是一门很棒的语言,你值得拥有!

展开阅读全文
打赏
1
4 收藏
分享
加载中
Auto-deref,学习了。
2015/10/11 16:40
回复
举报
曾赛博主

引用来自“南漂一卒”的评论

语法上看起来还是 Java 清晰、优雅~
嗯。这就是Rust有那么的功能需要付出的代价吧
2015/08/22 17:58
回复
举报
很好。
2015/08/22 14:32
回复
举报
语法上看起来还是 Java 清晰、优雅~
2015/08/22 13:58
回复
举报
更多评论
打赏
4 评论
4 收藏
1
分享
返回顶部
顶部