@haruka4434

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Rustのcloneメソッドについて

Q&A

私のコードに
form.input.clone();
というコードがあるのですがこれは
form.0.input;
とも書くことができます。

このときは後者のほうがパフォーマンスはいいのでしょうか?

cloneメソッドはヒープ上のデータをコピーするので実行コストが高いというのは知っているのですが.0.の書き方はどうなのかわかりません。

あと.0.の書き方に名前などあるのでしょうか?

0 likes

1Answer

私のコードに
form.input.clone();
というコードがあるのですがこれは
form.0.input;
とも書くことができます。

コードが無いので推測ではありますが、以下のようなケースを想定されているということでよろしいでしょうか?

struct Form(pub Inner);

struct Inner {
    input: ...
}

impl Deref for Form {
    type Target = Inner;

    fn deref(&self) -> &Inner {
        &self.0
    }
}

この場合、以下の2つのステートメントはどちらも同じ意味になります。

  • form.0.input
  • form.input

後者の場合、Form構造体自体はinputというフィールドは持っていないのですが、Form構造体はDerefトレイトを実装しているため、Inner構造体のフィールドも参照することが出来ます。

より具体的には、form.inputという式は以下の式に対するSyntax Sugerです。

Deref::deref(&form).input

このときは後者のほうがパフォーマンスはいいのでしょうか?

基本的にCloneはパフォーマンスに悪影響を与えることが多いですが、その影響の度合いは構造体がどのようなデータを持っているかにも依存します。構造体がヒープ上にデータを持つような場合(Box, Vec, Stringなど)、メモリが再確保され、ヒープ上のデータをコピーするためパフォーマンスが劣化します。逆に構造体がヒープ上にデータを持たない場合は、最適化によってコピー操作自体が省略されることもあります。

ただしCloneを行わない場合、form.0.inputフィールドはmoveされ、それ以降inputフィールドは使用できなくなります。またformの型が&Form&mut Formといったように参照型である場合、そもそもmove自体が出来ないため、明示的にクローンするか、あるいは&form.0.inputといったようにinputフィールドへの参照を返す必要があります。

moveについては、以下の記事などを参照されるとよいかと思います。

ちなみになぜform.input;と書けないかと言うと、上で見たようにこの式はDeref::deref(&form).input;という式に対するSyntax Sugerであり、derefメソッドは参照型を返すのですが、参照型からはmoveすることが出来ないからです。

蛇足ですが、どうしても参照型からmoveしたい場合は、takeイディオムと呼ばれる方法も存在します。

.0.の書き方に名前などあるのでしょうか?

このような書き方はRustのドキュメントではtuple indexingと呼ばれています。

1Like

Your answer might help someone💌