Большинство типов имеют определённый размер в байтах. Этот размер обычно
известен во время компиляции. Например, i32
— это 32 бита, или 4 байта.
Однако, существуют некоторые полезные типы, которые не имеют определённого
размера. Они называются «безразмерными» или «типами динамического размера». Один
из примеров таких типов — это [T]
. Этот тип представляет собой
последовательность из определённого числа элементов T
. Но мы не знаем, как
много этих элементов, поэтому размер неизвестен.
Rust понимает несколько таких типов, но их использование несколько ограничено. Есть три ограничения:
&[T]
будет работать, а [T]
— нет.А зачем это всё? Поскольку мы можем использовать [T]
только через указатель,
если бы язык не поддерживал безразмерные типы, мы бы не смогли написать такой
код:
impl Foo for str {
или
fn main() { impl<T> Foo for [T] { }impl<T> Foo for [T] {
Вместо этого, вам бы пришлось написать:
fn main() { impl Foo for &str { }impl Foo for &str {
Таким образом, данная реализация работала бы только для ссылок, и не поддерживала бы другие типы указателей. А реализацию для безразмерного типа смогут использовать любые указатели, включая определённые пользователем умные указатели (позже, когда будут исправлены некоторые ошибки).
Если вы пишете функцию, принимающую тип динамического размера, вы можете
использовать специальное ограничение ?Sized
:
struct Foo<T: ?Sized> { f: T, }
Этот ?
читается как «Т может быть размерным (Sized
)». Он означает, что это
ограничение особенное: оно разрешает использование некоторых типов, которые не
могли бы быть использованы в его отсутствие. Таким образом, оно расширяет
множество подходящих типов, а не сужает его. Это можно представить себе как если
бы все типы T
неявно были размерными (T: Sized
), а ?
отменял это
ограничение по-умолчанию.