所以我看到有理由禁止孤立特征实现,因为前向兼容性考虑(为了防止在库中添加进一步的特征实现而破坏使用类型特征的某个地方)并且它可能使编译更多难。但我想知道Rust社区认为哪种解决方法是最理想的解决方案:
(以防万一这背景不够:我正在尝试将rusqlite与chrono的DateTime
一起使用。所以我想实现rusqlite的FromSql
和ToSql
的{{1}}特征,但这显然不像我想象的那么简单 - 我现在刚刚开始使用Rust。)
DateTime<UTC>
结构(可能是最好的解决方法,但我觉得这只是一些不必要的工作复制)。DateTime
特征并给它一个别名,并为我的别名类型实现DateTime<UTC>
和FromSql
特征(但我认为这也不是微不足道的,当我尝试过它我无法让它工作,因为它仍被视为外部类型。)我希望有人可以向我解释如何最好地解决这个问题,从我纯粹的OOP经验中我只想继承ToSql
并实现接口但是(出于正当理由)这不是怎么回事它在Rust中完成......
答案 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();
}