変更の分類

以下にリストした全ての方針は変更のレベルで分類される:

「許容されうる破壊的変更」の分類は更新時に互換性の破壊の潜在性がある変更をカバーするが、必ずしも破綻するとは限らない。これらの変更の影響は慎重に検討されるべきである。具体的な実体はその変更とプロジェクトの管理者の方針に依存する。


許容されうる破壊的変更: デフォルトつきトレイトアイテムの追加

通常はデフォルトつきトレイトアイテムの追加は安全である。しかしながら、これはたまにコンパイルエラーを起こす。例えば、もし別のトレイトに同じ名前のメソッドが存在すればこれは曖昧さを生じさせる。

// Breaking change example

///////////////////////////////////////////////////////////
// Before
pub trait Trait {}

///////////////////////////////////////////////////////////
// After
pub trait Trait {
    fn foo(&self) {}
}

///////////////////////////////////////////////////////////
// Example usage that will break.
use updated_crate::Trait;
struct Foo;

trait LocalTrait {
    fn foo(&self) {}
}

impl Trait for Foo {}
impl LocalTrait for Foo {}

fn main() {
    let x = Foo;
    x.foo(); // Error: multiple applicable items in scope
}

名前の衝突におけるこの曖昧さは固有の実装では、それらがトレイトアイテムより優先されるため、存在しない点に注意せよ。

トレイトアイテム追加時の特殊な場合にはトレイトのオブジェクトセーフを参照されたい。

マイグレーション戦略:


許容されうる破壊的変更: 任意の固有アイテムの追加

通常は実装に固有のアイテムを追加するのは安全である。なぜなら固有のアイテムはトレイトのアイテムより優先される。ただし、もし実装されたトレイトのアイテムと同じ名前で異なるシグネチャなら、特定の場合では衝突して問題の原因になるかもしれない。

// Breaking change example

///////////////////////////////////////////////////////////
// Before
pub struct Foo;

///////////////////////////////////////////////////////////
// After
pub struct Foo;

impl Foo {
    pub fn foo(&self) {}
}

///////////////////////////////////////////////////////////
// Example usage that will break.
use updated_crate::Foo;

trait Trait {
    fn foo(&self, x: i32) {}
}

impl Trait for Foo {}

fn main() {
    let x = Foo;
    x.foo(1); // Error: this method takes 0 arguments but 1 argument was supplied
}

注意すべきはシグネチャが一致する場合で、これはコンパイル時のエラーにはならないだろう、だが実行時の挙動のこっそりとした変更になりうる (なぜならそれはもう異なる関数を実行している)。

マイグレーション戦略: