Ответ 1
std::raw::Slice
&[T]
, как вы заметили, "эквивалентен" структуре std::raw::Slice
. На самом деле, Slice
является внутренним представлением значения &[T]
, и да, это указатель и длина данных за этим указателем. Иногда такая структура называется "указателем жира", то есть указателем и дополнительной информацией.
Когда вы передаете значение &[T]
, вы действительно просто копируете его содержимое - указатель и длину.
Если это был недопустимый указатель на переменную "slice", значение len в выражении println() было бы 0, но это не так. Настолько эффективно копия не только значения указателя, но и полная копия структуры Slice. Это правильно?
Так, да, точно.
Означает ли это, что в целом допустимо вернуть a & [T] до тех пор, пока действительный внутренний указатель данных действителен, независимо от объема оригинала & [T], который возвращается, поскольку назначение & [T] операция копирования?
И это также верно. То, что вся идея заимствованных ссылок, в том числе заимствованные фрагменты, статически проверяется на использование, пока их референт жив. Когда DST наконец приземлится, фрагменты и регулярные ссылки будут еще более унифицированы.
(Мне кажется, что это чрезвычайно противоречиво интуитивно... поэтому, возможно, я недопонимаю, если я прав, если два и [T], указывающие на одни и те же данные, не могут быть действительными, потому что они не будут синхронизировать длины если вы измените один...)
И это на самом деле абсолютно актуальная проблема; это одна из проблем с псевдонимом. Однако Rust предназначен для предотвращения таких ошибок. Есть две вещи, которые делают наложение разрезов действительными.
Во-первых, срезы не могут изменить длину; нет методов, определенных на &[T]
которые позволят вам изменить его длину на месте. Вы можете создать производный срез из среза, но это будет новый объект.
Но даже если срезы не могут изменить длину, если данные могут быть мутированы через них, они все равно могут привести к катастрофе, если будут сглажены. Например, если значения в срезах являются экземплярами перечисления, изменение значения в таком псевдонимом фрагменте может сделать указатель на внутренности значения перечисления, содержащиеся в этом фрагменте, недействительными. Итак, во-вторых, Rust aliasable slices (&[T]
) неизменяемы. Вы не можете изменять значения, содержащиеся в них, и вы не можете принимать в них изменчивые ссылки.
Эти две функции (и проверки компилятора на время жизни) делают сглаживание срезов абсолютно безопасным. Однако иногда вам нужно изменить данные в срезе. И тогда вам нужен измененный фрагмент, называемый &mut [T]
. Вы можете изменить свои данные с помощью такого фрагмента; но эти фрагменты не являются алиасируемыми. Вы не можете создать два изменяемых фрагмента в одну и ту же структуру (например, массив), поэтому вы не можете сделать ничего опасного.
Обратите внимание, однако, что использование transformute transmute()
для преобразования среза в Slice
или наоборот является небезопасной операцией. &[T]
гарантированно статически корректно, если вы создаете его с использованием правильных методов, например, вызываете as_slice()
на Vec
. Однако, создавая его вручную с помощью структуры Slice
а затем трансформируя его в &[T]
, подвержено ошибкам и может легко segfault ваша программа, например, когда вы назначаете ее больше длины, чем на самом деле распределено.