web-dev-qa-db-ja.com

Rust 1つのタイプで特性のコピーとドロップを許可しないのはなぜですか?

から

タイプまたはその一部がCopyトレイトを実装している場合、RustではタイプにDropトレイトで注釈を付けることはできません。値がスコープ外になったときに型に何か特別なことが必要で、その型にCopyアノテーションを追加すると、コンパイル時エラーが発生します。

同じタイプでCopyDropを許可しないように設計が決定されたのはなぜですか?

13
sdgfsdh
  • Dropトレイトは、 [〜#〜] raii [〜#〜] コンテキストで使用されます。通常、オブジェクトが破棄されたときにリソースを解放/閉じる必要がある場合に使用されます。
  • 一方、Copy型は、memcpyでのみコピーできる簡単な型です。

これらの2つの説明により、それらが排他的であることがより明確になります。重要なデータをmemcpyすることは意味がありません。データをコピーし、コピーの1つを削除するとどうなりますか?他のコピーの内部リソースは信頼できなくなります。

実際、Copyは、関数を定義しないという点で、「実際の」特性でさえありません。これは、コンパイラに「単純なバイトコピーで自分自身を複製できます」と言う特別なマーカーです。したがって、実装がまったくないため、Copyのカスタム実装を提供することはできません。ただし、タイプをコピー可能としてマークすることはできます。

impl Copy for Foo {}

以上、派生:

#[derive(Clone, Copy)]
struct Foo { /* ... */ }

これは、すべてのフィールドがCopyを実装している場合にのみビルドされます。それ以外の場合、これは安全ではないため、コンパイラはコンパイルを拒否します。


例として、File構造体がCopyを実装していると仮定しましょう。もちろん、これはnotの場合であり、この例は間違っており、コンパイルできません。

fn drop_copy_type<T>(T x)
where
    T: Copy + Drop,
{
    // The inner file descriptor is closed there:
    std::mem::drop(x);
}

fn main() {
    let mut file = File::open("foo.txt").unwrap();
    drop_copy_type(file);
    let mut contents = String::new();

    // Oops, this is unsafe!
    // We try to read an already closed file descriptor:
    file.read_to_string(&mut contents).unwrap();
}
15

ドキュメント を引用します。

[...] [A] Drop を実装するタイプはCopyにすることはできません。これは、独自のリソース以外のリソースを管理しているためです size_of::<T> バイト。

4
hellow