为什么Rust禁止为外部结构实现外部trait?

8

我遇到了一个问题,即在我不拥有的类型上实现我不拥有的特征。然后我通过谷歌找到了与之完全相同的问题:如何在我不拥有的类型上实现我不拥有的特征?

令我困惑的是这种限制背后的动机。我来自Scala,在Scala中可以为外部类型拥有外部类型类实例。

为什么Rust会做出这样的限制呢?


6
假设有这样一个情景:创建A和创建B都为类型D的Bar实现了trait C中的foo方法,那么该选择哪个呢?这是基于观点的问题。 - Alexey Larionov
@AlexLarionov 有道理。 - Some Name
就我所知,Rust 设计中的一些人对 Haskell 的这个特性有非常糟糕的体验。在 Haskell 中,你可以为现有类型定义现有的 typeclasses,而某些包也会这样做,这会导致难以理解的错误和 bug。 - Jan Hudec
@AlexeyLarionov 针对在你自己的箱(crate)定义的类型的泛型,如何实现 traits 的实现(impl traits)呢? - Matias Pequeno
3个回答

2
如Alexey Larionov在评论中解释的那样,如果两个crate都可以为同一个struct实现trait,则会存在使用哪个trait实现的冲突。通过这种限制,Rust保证每个(struct,trait)对在所有crate中最多只有一个实现。
如果你发现自己需要为外部struct实现外部trait,则可以利用Rust New Type Idiom
通过将外部struct包装在新类型中,您可以在该新类型上实现任何外部trait。
虽然新类型与外部struct不同,但您可以使用New Type Idiom文档中解释的.0语法引用包装的类型。

如果两个 crate 可以为同一个结构体实现 trait,那么就会出现使用哪个 trait 实现的冲突。嗯,按照 C# 的方式,在文件的作用域中“导入扩展 trait”是非常合理的做法。 - Alexandre Daubricourt

1
我刚刚阅读了Rust Book关于实现traits的章节,正如@AlexLarionov在评论中提到的那样,选择适当的实现是不可能的:
“但我们不能在外部类型上实现外部traits。例如,我们无法在聚合器crate中为Vec实现Display trait,因为Display和Vec是在标准库中定义的,而不是本地的聚合器crate。这个限制是程序所谓的一致性属性的一部分,更具体地说是孤儿规则,因为父类型不存在。该规则确保其他人的代码无法破坏您的代码,反之亦然。没有这条规则,两个crate可以为同一类型实现相同的trait,而Rust将不知道使用哪个实现。”

2
这引出了一个问题,为什么Rust没有为我们在Vec上实现Display - Christian Bongiorno

1
与其他人所说的不同,尽管目前还不可能,但我不认为这是一个好的限制,这是我的观点。
如果箱子A和箱子B实现了箱子C的结构,并使用了whatever::external_trait
那么在它们各自的范围内,箱子A和箱子B可以使用自己的external_trait实现。
这样的功能将来可能会有。
请参阅Crates should allow private impl of external traits for external structs #493以了解进展情况。

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