为外来类型

时间:2016-02-02 18:18:58

标签: rust

所以我看到有理由禁止孤立特征实现,因为前向兼容性考虑(为了防止在库中添加进一步的特征实现而破坏使用类型特征的某个地方)并且它可能使编译更多难。但我想知道Rust社区认为哪种解决方法是最理想的解决方案:

(以防万一这背景不够:我正在尝试将rusqlitechronoDateTime一起使用。所以我想实现rusqlite的FromSqlToSql的{​​{1}}特征,但这显然不像我想象的那么简单 - 我现在刚刚开始使用Rust。)

  • fork rusqlite并实现特性。 (我觉得这不是最好的方式,因为可能只是我需要这个特性实现,所以我可能最终必须保持自己的叉子更新。我也不是能够实现这些特性,因为有些复杂的泛型事物我还不完全理解。
  • 实现我自己的DateTime<UTC>结构(可能是最好的解决方法,但我觉得这只是一些不必要的工作复制)。
  • 以某种方式“复制”DateTime特征并给它一个别名,并为我的别名类型实现DateTime<UTC>FromSql特征(但我认为这也不是微不足道的,当我尝试过它我无法让它工作,因为它仍被视为外部类型。)

我希望有人可以向我解释如何最好地解决这个问题,从我纯粹的OOP经验中我只想继承ToSql并实现接口但是(出于正当理由)这不是怎么回事它在Rust中完成......

2 个答案:

答案 0 :(得分:3)

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

extern crate a;
extern crate b;

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

pub struct MySomeStruct(SomeStruct);

impl SomeTrait for MySomeStruct {
    ...
}

在这里你创建了一个围绕外部结构的包装器,由于这个包装器是一个完全不同的类型,它属于你的包,你可以自由地为它实现a::SomeTrait。这类似于你的第二点,除了你绝对不需要从头开始重新实现这个类型。

当然,您无法在SomeStruct上调用MySomeStruct的所有方法。您必须转发所需的所有方法,或者在不再需要其特征实现时解包内部值,或者您可以impl Deref for MySomeStruct { type Target = SomeStruct; ... },但后者被视为反模式。

答案 1 :(得分:2)

我不确定什么是最惯用的,但看起来最好的方法是使用newtype模式,这是一个带有一个字段的元组结构。这将创建一个与旧类型不同的新类型,您可以实现该新类型的特征。要使用特征方法,您需要将其包装在newtype中,但是要使用常规方法,您将使用普通的struct而不使用newtype包装。

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();
}