为外部类型实现外部特性

11

因为前向兼容性考虑(防止在类型的 trait 使用处添加另一个 trait 实现导致库中断),以及可能会使编译变得更加困难,所以我发现禁止孤儿 trait 实现是有理由的。但我想知道 Rust 社区认为哪种解决方法最理想:

(以防这不够背景信息:我正在尝试使用 rusqlitechronoDateTime。所以我想要为 DateTime<UTC> 实现 rusqlite 的 FromSqlToSql traits,但显然这并不像我想象的那么容易——我目前刚开始接触 Rust。)

  • 分支 rusqlite 并实现 trait。(我觉得这不是最好的做法,因为也许只是我需要 trait 实现,所以我可能不得不保持自己的分支更新。而且我无法实现这些 traits,因为存在一些复杂的泛型问题,我还没有完全理解。
  • 实现自己的 DateTime 结构体(这可能是最好的解决方法,但我觉得这只是一些不必要的工作复制)。
  • 以某种方式“复制”DateTime<UTC> trait 并给它一个别名,并为我的别名类型实现 FromSqlToSql traits(然而,我认为这也不是简单的,当我尝试时,它仍然被视为外部类型,所以我无法让它起作用)。

我希望有人能向我解释如何最好地解决这个问题,根据我的纯面向对象编程经验,我只想能够继承 DateTime 并实现接口,但是(出于有效的原因),这不是 Rust 的做法...

2个回答

16

最简单的方法是使用 newtype 模式:

extern crate a;
extern crate b;

use a::SomeTrait;
use b::SomeStruct;

pub struct MySomeStruct(SomeStruct);

impl SomeTrait for MySomeStruct {
    ...
}

在这里,您需要围绕外部结构创建一个包装器,由于此包装器是属于您的 crate 的完全不同类型,因此可以自由地为其实现 a::SomeTrait。这类似于您的第二点,只是您绝对不需要从头重新实现该类型。

当然,您将无法在 MySomeStruct 上调用 SomeStruct 的所有方法。您必须要么转发您想要的所有方法,要么在不再需要其 trait 实现时取消内部值的包装,或者您可以使用 impl Deref for MySomeStruct { type Target = SomeStruct; ... },但后者被认为是一种反模式。


为什么它被认为是反模式? - Folling
2
请看这个链接:https://dev59.com/xFcO5IYBdhLWcg3w5lbX - Vladimir Matveev

4

我不确定最惯用的方法是什么,但看起来最佳做法是使用新类型模式,它是一种只有一个字段的元组结构体。这将创建与旧类型不同的新类型,并且您可以为该新类型实现特性。要使用特性方法,您需要将其包装在新类型中,但要使用普通方法,您将使用没有新类型包装器的普通结构体。

struct MyType(TheirType);

impl TheTrait for MyType {
    ....
}

fn main() {
    let a = TheirType::new(....);
    a.method_on_their_type();
    let b = MyType(TheirType::new(....));
    b.method_on_the_trait();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接