没有类只有接口的语言(rust)如何实现继承又避免代码重复?

发布于 2022-09-01 12:41:31 字数 1635 浏览 15 评论 0

rust没有类只有接口, 不过接口可以继承也可以为method定义默认实现, 可是接口只能声明method不能声明成员属性, 于是default method里也不能直接访问成员属性

如果某些default method一定要访问成员属性才能实现的话, 除了在接口里写一大堆的getter/setter外有什么方法能解决这个问题呢?

现在用getter/setter写出来是这样下面↓这样, 然后每次impl都要复制一大段的getXXX/setXXX...

pub trait Sprite2D<T>: Sprite<T> {
    fn get_position(&self) -> Vector2D;
    fn set_position(&mut self, p: Vector2D);
    fn get_direction(&self) -> f64;
    fn set_direction(&mut self, d: f64);
    fn get_scale_x(&self) -> f64;
    fn set_scale_x(&mut self, sx: f64);
    fn get_scale_y(&self) -> f64;
    fn set_scale_y(&mut self, sy: f64);

    fn get_matrix(&self) -> Matrix2D {
        let position = self.get_position();
        let mat_s = Matrix2D::create_scale(self.get_scale_x(), self.get_scale_y());
        let mat_r = Matrix2D::create_rotate(self.get_direction());
        let mat_p = Matrix2D::create_translate(position.x(), position.y());
        mat_s.append(&mat_r).append(&mat_p)
    }

    fn get_inv_matrix(&self) -> Matrix2D {
        self.get_matrix().inv()
    }

    fn translate(&mut self, dx: f64, dy: f64) {
        let pos = self.get_position() + Vector2D::new(dx, dy);
        self.set_position(pos);
    }

    fn rotate(&mut self, rad: f64) {
        let dir = self.get_direction() + rad;
        self.set_direction(dir);
    }

    fn scale(&mut self, sx: f64, sy: f64) {
        let n_sx = self.get_scale_x() * sx;
        let n_sy = self.get_scale_y() * sy;
        self.set_scale_x(n_sx);
        self.set_scale_y(n_sy);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

遥远的她 2022-09-08 12:41:31

我个人的建议,可以有以下办法。

方案一,手动添加继承类型和基类型之间的转换关系:
设计一个基类型 BaseSprite, 它有一系列的成员函数。
所有的子类都必须有一个基类型的成员变量,并且实现AsRef<BaseSprite>

struct BaseSprite;

struct Sprite1 {
  base: BaseSprite,
  data: i32,
}

impl AsRef<BaseSprite> for Sprite1 {

    fn as_ref(&self) -> &BaseSprite {
        &self.base
    }
}

// 如果需要对所有的 Sprite类型处理,可以写泛型函数:
fn do_something<T>(s: T) where T: AsRef<BaseSprite) {
}

这么设计的缺点是每次调用基类型的函数,需要先使用 as_ref()。至于每个子类型都需要实现trait,其实可以用一个宏来完成。

方案二,利用Deref这个特殊的trait,实现基类型和子类型之间的转换:
设计一个基类型 BaseSprite, 它有一系列的成员函数。
所有的子类都必须有一个基类型的成员变量,并且实现Deref<Target=BaseSprite>

use std::ops::Deref;

struct BaseSprite;

struct Sprite1 {
  base: BaseSprite,
  data: i32,
}

impl Deref for Sprite1 {
    type Target = BaseSprite;
    
    fn deref<'a>(&'a self) -> &'a BaseSprite {
        &self.base
    }
}

这样一来,所有子类型调用成员函数时,会自动去寻找基类型的成员函数。智能指针就是通过这种方式直接透明调用内部成员的方法的。

方案一和方案二对比,各有优缺点。方案一写起来比较麻烦,但是可以实现多继承;方案二相对简洁,但是不能实现多继承,一个类型只能实现一个Deref

情丝乱 2022-09-08 12:41:31

Tarit Object啊

getter,setter 不需要啊,直接pub就行了啊。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文