Rust 如何在不支持继承的情况实现 getter/setter 的代码复用? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiaopanzi
V2EX    Rust

Rust 如何在不支持继承的情况实现 getter/setter 的代码复用?

  •  
  •   xiaopanzi 2021 年 5 月 26 日 3401 次点击
    这是一个创建于 1769 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Rust 不支持继承,这对从 Java 转过来的人有点困扰。近日在读设计模式的书籍,里面有个例子是:有一个抽象的 Duck 类,它有一个属性是 FlyBehavior (是个接口)。

    abstract class Duck { private FlyBehavior flyBehavior; public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public FlyBehavior getFlyBehavior() { return this.flyBehavior; } } 

    再 Rust 里面,只能这样写:

    trait Duck { fn get_fly_behavior(&self) -> &dyn FlyBehavior; fn set_fly_behavior(&mut self, fly_behavior: Box<dyn FlyBehavior>); } 

    这样的话,所有实现 Duck 的其他 struct 都必须写 一模一样 的 getter/setter 。

    所以,在 Rust 中针对这个场景,如何能够实现代码复用?

    13 条回复    2021-05-26 15:55:09 +08:00
    jedrek
        1
    jedrek  
       2021 年 5 月 26 日
    吃饭有吃饭的方式,不需要用吃屎的方式吃饭
    VDimos
        2
    VDimos  
       2021 年 5 月 26 日 via Android
    写个宏呗,derive macro 也可以
    iikebug
        3
    iikebug  
       2021 年 5 月 26 日
    1 楼说的对,不要用吃屎的方式吃饭
    Vegetable
        4
    Vegetable  
       2021 年 5 月 26 日
    你是换了语言,不是换了一种 JAVA,不要被写法限制是想法
    xiaopanzi
        5
    xiaopanzi  
    OP
       2021 年 5 月 26 日
    @jedrek 请大佬明示。用 Rust 模仿 Java 确实不妥。但如果要实现类似功能(比如这里的 Strategy Pattern ),Rust 的“吃饭”方式应该是什么?
    xiaopanzi
        6
    xiaopanzi  
    OP
       2021 年 5 月 26 日
    @VDimos 谢谢提示。我学习一下 Macro 的写法。
    Jirajine
        7
    Jirajine  
       2021 年 5 月 26 日 via Android
    rust 有 sum type,大多数情况下传统 oo 里的继承都是不必要的。
    如果是多个类型共同的行为,那就用 trait 。
    xiaopanzi
        8
    xiaopanzi  
    OP
       2021 年 5 月 26 日
    @Jirajine I see 。我能理解只有 trait 而不用继承的 trade-off 。那么具体到对于“试图共享 get/set 的具体实现”这一基本问题,在 Rust 中是不是除了重复就别无他法(不引入 macro 的情况下)?另外,Rust 中针对 Strategy Pattern 是否有更好的解决方案,而不用写 get/set ?再进一步,鉴于 Rust 不是传统的 OO 语言,是不是很多时候写 Design Pattern 就注定了是“吃屎”的写法?
    Jirajine
        9
    Jirajine  
       2021 年 5 月 26 日
    @xiaopanzi #8 trait 中方法的实现当然可以共享,但你这种共享属性的用法肯定不适用。你把 Java 专用的 Design Pattern 八股文往其他语言上套,那当然是“吃屎”的写法。

    因为范式不同,代码组织的方式也不同,很难直接套上。你要类似的可以看这个 https://rust-unofficial.github.io/patterns/patterns/behavioural/strategy.html

    被 JavaOOP 设计模式毒害太深的话可以学一下 haskell,放宽思路,回过头来就豁然开朗了。
    Jirajine
        10
    Jirajine  
       2021 年 5 月 26 日
    @xiaopanzi #8 总的来说,一般使用继承的场景,表达 sum type -> 用 enum,表达 subtyping -> 用泛型,表达接口 ->用 trait 。
    jedrek
        11
    jedrek  
       2021 年 5 月 26 日   1
    设计模式的出现,某种程度上是针对某种某类编程语言特点或弥补它的不足,若有些编程语言没有这些问题,自不必要考虑这些设计模式,硬套只会创造本不应有的问题。

    getter/setter 概念是 OOP 宗教化出现的东西,本质上控制某个属性读写权限,实际使用中也是如此。Rust 的设计没有这种将值函数化的意图,

    如果你仅仅想使用 Rust 实现策略模式,可以这样写

    ```rust
    fn main() {
    Context { strategy: StrategyA }.execute();
    Context { strategy: StrategyB }.execute();
    }

    struct Context<T: Strategy> {
    strategy: T
    }
    impl<T: Strategy> Context<T> {
    fn execute(&self) {}
    }

    trait Strategy {
    fn do_something();
    }

    struct StrategyA;
    struct StrategyB;

    impl Strategy for StrategyA {
    fn do_something() { }
    }

    impl Strategy for StrategyB {
    fn do_something() { }
    }
    ```
    xiaopanzi
        12
    xiaopanzi  
    OP
       2021 年 5 月 26 日
    @Jirajine 学习了。多谢!
    xiaopanzi
        13
    xiaopanzi  
    OP
       2021 年 5 月 26 日
    @jedrek Thanks 。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     987 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 22:18 PVG 06:18 LAX 15:18 JFK 18:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86