Небезопасный Rust

Это серьёзная, большая, сложная и опасная тема. Настолько серьёзная, что я написала про неё отдельную книгу. (Прим. перевод.: речь идёт о широко известной в среде Rust-программистов книге Растономикон).

На самом деле любой язык, из которого можно вызывать функции на другом языке, уже является небезопасным, потому что, например, в C можно делать любые плохие вещи. Java, Python, Ruby, Haskell... все они крайне небезопасны из-за присутствия в них интерфейса внешних функций (Foreign Function Interfaces, FFI).

Rust следует этой истине, разделяя себя на два языка — Безопасный и Небезопасный Rust. Пока что мы работали только с Безопасным. Это на 100% безопасно... пока мы не используем FFI.

Небезопасный Rust — это надмножество над Безопасным Rust. Он такой же, как и Безопасный Rust со всей семантикой и правилами, но вам доступны дополнительные возможности. Они дико небезопасны и могут привести к ужасному Неопределённому Поведению (Undefined Behaviour, UB), которым так славится C.

Ещё раз скажу, что мы имеем дело с действительно огромной темой, в которой много интересных частных случаев. Я на самом деле не хочу иметь в ними дела (ну, ладно, хочу; уже имела; читайте книгу). К счастью, в случае связных списков мы можем игнорировать большинство из них.

ГОЛОС ЗА КАДРОМ: Это была ложь, но в 2015 она казалась правдой.

Главный инструмент Небезопасного Rust, который мы будем использовать — это сырые указатели. Сырые указатели — это, по сути, указатели из C. У них нет собственных правил псевдонимизации (aliasing). У них нет времени жизни. Они могут быть нулевыми. Они могут быть невыровненными. Они могут быть висячими. Они могут указывать на неинициализированную память. Их можно приводить к целым числам и обратно. Их можно приводить к указателям на другой тип. Неизменяемый указатель? Приводим к изменяемому! Мы можем делать практически всё, что угодно, а это значит, что практически всё, что угодно, может пойти не так.

ГОЛОС ЗА КАДРОМ: нет собственных правил псевдонимизации, да? Эх, молодо-зелено.

Это довольно неприятная штука и, честно говоря, вы были бы гораздо счастливее, оставаясь в рамках Безопасного Rust. К сожалению, мы хотим писать связные списки, а связные списки действительно ужасны. И это значит, что нам придётся использовать небезопасные указатели.

Есть два вида сырых указателей: *const T и *mut T. Предполагается, что они соответствуют const T* и T* из языка C, но нам, по большому счёту, всё равно, что они означают в C. *const T можно разыменовать только в &T, но, как и в случае с изменяемостью переменной, это всего лишь способ защиты от некорректного использования. Его можно обойти, если сначала надо привести *const к *mut. Впрочем, если у вас нет права менять объект, на который ссылается указатель, у вас возникнут проблемы.

В любом случае, мы лучше разберёмся в теме, если напишем немного кода. А пока для нас *mut T будет значить &unchecked mut T!