Пример: ссылки
// Copyright 2026 Google LLC
// SPDX-License-Identifier: Apache-2.0
fn main() {
let mut boxed = Box::new(123);
let a: *mut i32 = &mut *boxed as *mut i32;
let b: *mut i32 = std::ptr::null_mut();
println!("{:?}", *a);
println!("{:?}", b.as_mut());
}
Убедитесь, что синтаксис понятен
-
Тип
Box<i32>— это ссылка на целое число в куче, которым владеет box. -
Тип
*mut i32— так называемый сырой указатель на целое число, владение которым компилятор не знает. Программисты должны сами обеспечивать соблюдение правил без помощи компилятора.- Примечание: сырые указатели не передают Rust информацию о владении. Указатель может семантически владеть данными или семантически заимствовать их, но эта информация существует только в голове программиста.
-
Выражение
&mut *boxed as *mut _:*boxed— это …&mut *boxed— это …- наконец,
as *mut i32приводит ссылку к указателю.
-
Ссылки, такие как
&mut i32, «заимствуют» то, на что указывают. Это система владения Rust.
Убедитесь, что владение понятно
-
Пройдите по коду:
- (Строка 3) Создаёт сырой указатель на
123: разыменовывает box, создаёт новую ссылку и приводит её к указателю. - (Строка 4) Создаёт сырой указатель со значением NULL
- (Строка 7) Преобразует сырой указатель в
Optionс помощью.as_mut()
- (Строка 3) Создаёт сырой указатель на
-
Обратите внимание, что указатели в Rust могут быть нулевыми (в отличие от ссылок).
-
Скомпилируйте, чтобы увидеть сообщения об ошибках.
-
Обсудите
- (Строка 6)
println!("{:?}", *a);- Префиксная звёздочка разыменовывает сырой указатель.
- Это явная операция. Тогда как обычные ссылки чаще всего разыменовываются неявно благодаря трейту
Deref. Это называется «auto-deref». - Разыменование сырого указателя — небезопасная операция.
- Требует небезопасного блока.
- (Строка 7)
println!("{:?}", b.as_mut());as_mut()— небезопасная функция.- Вызов небезопасной функции требует небезопасного блока.
- (Строка 6)
-
Продемонстрируйте: исправьте код (добавьте небезопасные блоки) и снова скомпилируйте, чтобы показать работающую программу.
-
Продемонстрируйте: замените
as *mut i32наas *mut _и покажите, что код компилируется.- В приведении можно частично опустить целевой тип. Компилятор Rust знает, что источник приведения —
&mut i32. Такой тип ссылки можно преобразовать только в один тип указателя:*mut i32.
- В приведении можно частично опустить целевой тип. Компилятор Rust знает, что источник приведения —
-
Добавьте комментарии о безопасности:
- Мы говорили, что небезопасный код отмечает переход ответственности от компилятора к программисту.
- Как показать, что мы подумали о своей необычной ответственности, когда писали небезопасный код? Комментарии о безопасности.
- Комментарии о безопасности объясняют, почему небезопасный код корректен.
- Без комментария о безопасности небезопасный код не является безопасным.
-
Обсудите: использовать один большой небезопасный блок или два меньших:
- Возможность использовать один небезопасный блок вместо нескольких.
- Использование нескольких блоков позволяет писать максимально конкретные комментарии о безопасности.
Предлагаемое решение
// Copyright 2026 Google LLC
// SPDX-License-Identifier: Apache-2.0
fn main() {
let mut boxed = Box::new(123);
let a: *mut i32 = &mut *boxed as *mut i32;
let b: *mut i32 = std::ptr::null_mut();
// SAFETY: `a` — ненулевой указатель на i32, он инициализирован и всё ещё
// выделен.
println!("{:?}", unsafe { *a });
// SAFETY: `b` — нулевой указатель, который `as_mut()` преобразует в `None`.
println!("{:?}", unsafe { b.as_mut() });
}