2016-04-12 9 views
2

ハスケルのようないくつかの言語は、値渡しと参照渡しを区別しません。コンパイラはヒューリスティックでもっとも効率的な呼び出し規約を選択することができます。ヒューリスティックの例は、Linux x64 ABIの場合です。パラメータのサイズが16バイトを超える場合は、ポインタをスタックに渡します。それ以外の場合は、レジスタに値を渡します。なぜRustは値で呼び出しを行い、参照によって呼び出しますか?

値渡しと参照渡しの両方の考え方(勿論変更不可)を錆に保ち、ユーザーに選択させてもらうことの利点は何ですか?

値が変更されたと見なされると、参照渡し+コピーの構文砂糖が値渡しの場合がありますか?

答えて

8

2つのこと:

  1. 錆が一定値渡しを変えていくには、同様のヒューリスティックに基づいて、参照渡しに呼び出します。
  2. 値渡しは所有権移転を示し、参照渡しは借用を示します。これらは非常に異なっており、あなたが求めているasmレベルの懸念から完全に直交しています。

つまり、Rustでは、これら2つの形式が異なるセマンティクスを持ちます。しかし、それでも最適化を行うことはできません。

+0

私は2に同意します。しかし、これは型チェックレベルのようですので、タイプチェックの後で - コード生成が同一であることができますか? –

+0

@ŁukaszLew:はい、それは*別の問題であるかどうかは完全にわかります:) –

0

:1で生成されたコードを見て、見ることができるようにそれは、シンタックスシュガーではありません

[編集はリリースモードで動作するように変更さexampled]。

これらの関数を考える:1が他のシンタックスシュガーた場合

fn by_value(v: (u64, u64)) -> u64 { 
    v.0 + v.1 
} 

fn by_ref(v: &(u64, u64)) -> u64 { 
    v.0 + v.1 
} 

そして、我々は彼らが同じアセンブリコード、または少なくとも同じ呼び出し規則を生成することを期待したいです。 (see details、リリースモードを使用):しかし、実際には、我々はby_valuerdiレジスタにvへのポインタを渡し、値を取得するためにそのポインタに従わなければならないのに対しby_refは、rdirsiレジスタにvを渡すことがわかり

by_value: 
    movq 8(%rdi), %rax 
    addq (%rdi), %rax 
    retq 

by_ref: 
    leaq (%rdi,%rsi), %rax 
    retq 
+1

あなたは最適化でコンパイルされていないようです。 [あなたのコードのこのバージョン](https://play.rust-lang.org/?gist=6fd877dbbaa0cded95220a00afc1b6e2&version=stable&backtrace=0)(オプティマイザが機能を完全に削除するのを防ぐためのすべての回転をメモしてください)とリリースでのコンパイルmode *では、両方の関数がアセンブリ 'leaq \t 1(%rdi)、%rax;にコンパイルされます。 retq'。レジスタのプッシュとポップに関するすべての迷惑メールが最適化されていることに注意してください。 – Shepmaster

+0

あなたはそうです、最適化モードでは同じになります。私はもう少し複雑な例に変更しました。これは異なる動作を示しています。 – reinerp

+0

最新の変更では、リンゴとリンゴを比較していません。 [値のサイズの確認](https://play.rust-lang.org/?gist=02d1017d548d2d5ea6ee0cb6cf25a511&version=stable&backtrace=0)は、2つの 'u64 'のタプルが16バイトで、参照が8バイトであることを示しています。オプティマイザは、8バイトが16よりも優れていると判断した可能性があります。 – Shepmaster

関連する問題