Небезопасные операции
В качестве введения в этот раздел, чтобы цитировать официальную документацию, "следует стараться минимизировать количество небезопасного кода в кодовой базе". С этим в виду, давайте начнем! Небезопасные аннотации в Rust используются для обхода защит, установленных компилятором; конкретно, unsafe используется для четырех основных вещей:
- разыменовывание сырых указателей
- вызов функций или методов, которые являются
небезопасными
(в том числе вызов функции через FFI, см. [предыдущую главу книги)
- доступ к или модификация статических изменяемых переменных
- реализация небезопасных трейтов
Сырые указатели
Сырые указатели *
и ссылки &T
работают аналогично, но ссылки всегда безопасны, потому что гарантируется, что они указывают на валидные данные из-за проверщика заимствования. Разыменование сырого указателя можно сделать только через небезопасный блок.
fn main() {
let raw_p: *const u32 = &10;
unsafe {
assert!(*raw_p == 10);
}
}
Вызов небезопасных функций
Некоторые функции могут быть объявлены как небезопасные
, что означает, что ответственность за обеспечение правильности ложится на программиста, а не на компилятор. Одним примером является [std::slice::from_raw_parts
], которая создаст срез, зная указатель на первый элемент и длину.
use std::slice;
fn main() {
let some_vector = vec![1, 2, 3, 4];
let pointer = some_vector.as_ptr();
let length = some_vector.len();
unsafe {
let my_slice: &[u32] = slice::from_raw_parts(pointer, length);
assert_eq!(some_vector.as_slice(), my_slice);
}
}
Для slice::from_raw_parts
одно из предположений, которое должно быть соблюдено, заключается в том, что указатель, переданный в функцию, указывает на валидную память и что память, на которую он указывает, имеет правильный тип. Если эти инварианты не соблюдаются, то поведение программы не определено и невозможно预知ить, что произойдет.