Заимствование значения
Как мы видели раньше, вместо передачи владения при вызове функции можно позволить функции заимствовать значение:
// Copyright 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заимствует две точки и возвращает новую точку. - Вызывающий код сохраняет владение входными данными.
Этот слайд повторяет материал о ссылках из первого дня, немного расширяясь на аргументы функций и возвращаемые значения.
Для дальнейшего изучения
Заметки о возвратах со стека и инлайнинге:
-
Покажите, что возврат из
addдёшев, потому что компилятор может устранить операцию копирования, встроив вызовaddвmain. Измените приведённый код, чтобы он выводил адреса на стеке, и запустите его в Playground или посмотрите ассемблер в Godbolt. На уровне оптимизации «DEBUG» адреса должны меняться, а при «RELEASE» остаются одинаковыми:// Copyright 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 два
i32, из которых состоит точка, возвращаются в двух регистрах (eax и edx).