Трейт Sized
Трейт Sized - это маркерный трейт, который
указывает компилятору, что размер типа известен
во время компиляции. Все типы с фиксированным
размером, такие как i32, bool
или [u8; 4], автоматически реализуют
этот трейт. Типы с неизвестным размером,
например str или [T], не реализуют
Sized и называются DST (dynamically sized types).
По умолчанию все параметры обобщённых функций
имеют неявную границу Sized.
Синтаксис
fn func<T: Sized>(x: T) { }
fn func<T: ?Sized>(x: &T) { }
Запись ?Sized снимает неявное ограничение
и позволяет принимать типы с неизвестным размером
по ссылке.
Пример
Давайте убедимся, что типы с фиксированным
размером реализуют трейт Sized:
fn check_sized<T: Sized>() {
println!("type is Sized");
}
fn main()
{
check_sized::<i32>();
check_sized::<bool>();
check_sized::<[u8; 4]>();
}
Результат выполнения кода:
type is Sized
type is Sized
type is Sized
Пример
Давайте рассмотрим, как работает ограничение
?Sized. Тип str не реализует
Sized, поэтому его можно передать только
по ссылке:
fn print_len<T: ?Sized>(x: &T) {
println!("ok");
}
fn main()
{
let s: &str = "abcde";
print_len(s);
}
Результат выполнения кода:
ok
Пример
Давайте проверим, что будет, если попытаться
вернуть тип без известного размера напрямую.
Такой код не скомпилируется, потому что
возвращаемое значение должно быть Sized:
fn bad() -> str {
"abcde"
}
fn main()
{
let res = bad();
}
Компилятор выдаст ошибку:
error[E0277]: the size for values of type `str` cannot be known at compilation time
Чтобы исправить это, нужно вернуть ссылку
&str или взять тип в Box:
fn good() -> &'static str {
"abcde"
}
fn main()
{
let res = good();
println!("{}", res);
}
Результат выполнения кода:
"abcde"
Смотрите также
-
трейт
Trait,
который описывает общее поведение типов -
трейт
dyn Trait,
который используется для динамической диспетчеризации -
трейт
Trait Bound,
который задаёт ограничения на обобщённые типы -
трейт
Copy,
который позволяет копировать значения простым присваиванием