Rustのcloneメソッドについて
Q&A
私のコードに
form.input.clone();
というコードがあるのですがこれは
form.0.input;
とも書くことができます。
このときは後者のほうがパフォーマンスはいいのでしょうか?
cloneメソッドはヒープ上のデータをコピーするので実行コストが高いというのは知っているのですが.0.の書き方はどうなのかわかりません。
あと.0.の書き方に名前などあるのでしょうか?
Q&A
私のコードに
form.input.clone();
というコードがあるのですがこれは
form.0.input;
とも書くことができます。
このときは後者のほうがパフォーマンスはいいのでしょうか?
cloneメソッドはヒープ上のデータをコピーするので実行コストが高いというのは知っているのですが.0.の書き方はどうなのかわかりません。
あと.0.の書き方に名前などあるのでしょうか?
私のコードに
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
と呼ばれています。