値の借用
前に見たように、関数を呼び出すときに所有権を移動する代わりに、 関数にその値を 借用 させることができます:
// 著作権 2023 Google LLC // SPDX-License-Identifier: Apache-2.0 #[derive(Debug)] struct Point(i32, i32); fn add(p1: &Point, p2: &Point) -> Point { Point(p1.0 + p2.0, p1.1 + p2.1) } fn main() { let p1 = Point(3, 4); let p2 = Point(10, 20); let p3 = add(&p1, &p2); println!("{p1:?} + {p2:?} = {p3:?}"); }
add関数は 2 つのポイントを 借用 し、新しいポイントを返します。- 呼び出し元は入力の所有権を保持します。
このスライドは 1 日目の参照に関する内容の復習であり、 関数引数と戻り値も少し含めるように内容を広げています。
さらに調べること
スタック上での戻り値とインライン化に関するメモ:
-
addからの値の返却が低コストであることを示してください。これは、コンパイラが add の呼び出しを main にインライン化することでコピー操作を削除できるためです。上の コードをスタックアドレスを表示するように変更し、Playground で実行するか、 Godbolt でアセンブリを見てください。“DEBUG” 最適化レベルではアドレスは変わるはずですが、“RELEASE” 設定に変更すると 同じままです:// 著作権 2023 Google LLC // SPDX-License-Identifier: Apache-2.0 #[derive(Debug)] struct Point(i32, i32); fn add(p1: &Point, p2: &Point) -> Point { let p = Point(p1.0 + p2.0, p1.1 + p2.1); println!("&p.0: {:p}", &p.0); p } pub fn main() { let p1 = Point(3, 4); let p2 = Point(10, 20); let p3 = add(&p1, &p2); println!("&p3.0: {:p}", &p3.0); println!("{p1:?} + {p2:?} = {p3:?}"); } -
Rust コンパイラは自動インライン化を行えます。これは関数単位で
#[inline(never)]を使って無効にできます。 -
いったん無効にすると、表示されるアドレスはすべての最適化レベルで 変わります。Godbolt や Playground を見ると、この場合の値の返却は ABI に依存することがわかります。たとえば amd64 では、ポイントを構成する 2 つの i32 は 2 つのレジスタ(eax と edx)で返されます。