Почему методы типажей не могут иметь реализацию по умолчанию, возвращающую self как объект типажа

Я новичок в ржавчине и пытаюсь разобраться в этой ошибке. Если я использую, напишите этот код

pub struct A {}

pub trait Trait {
    fn stuff(self: Box<Self>) -> Box<dyn Trait>;
}

impl Trait for A {
    fn stuff(self: Box<Self>) -> Box<dyn Trait> {
        self
    }
}

Он компилируется нормально.

Но если я напишу это

pub struct A {}

pub trait Trait {
    fn stuff(self: Box<Self>) -> Box<dyn Trait> {
        self
    }
}

impl Trait for A {}

я получаю ошибку

error[E0277]: the size for values of type `Self` cannot be known at compilation time
 --> src/lib.rs:5:9
  |
5 |         self
  |         ^^^^ doesn't have a size known at compile-time
  |
  = note: required for the cast from `Box<Self>` to `Box<(dyn Trait + 'static)>`
help: consider further restricting `Self`
  |
4 |     fn stuff(self: Box<Self>) -> Box<dyn Trait> where Self: Sized {
  |                                                 +++++++++++++++++

Почему размер self должен быть задан по умолчанию, а не при реализации в структуре? В обоих случаях я использую указатель Box, поэтому размер на самом деле не нужен, поскольку независимо от того, что указано в аргументе типа, Box всегда будет иметь один и тот же размер.

A — это Sized, и компилятор это знает. Если вы попытаетесь impl Trait for str сделать это, он не скомпилируется. Из этого можно упростить черты: let b: Box<str> = "foo".into(); let d: Box<dyn Debug> = b; Хотя я точно не знаю, зачем это нужно Sized. stackoverflow.com/questions/57398118/…?
Ry- 01.06.2024 01:14
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
1
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете предоставить реализацию по умолчанию, возвращающую Box<Self> как Box<dyn Trait>, ограничив Self такими, чтобы они были Sized и 'static:

pub trait Trait {
    fn stuff(self: Box<Self>) -> Box<dyn Trait>
    where
        Self: Sized + 'static,
    {
        self
    }
}

Для этого требуется 'static, потому что это предполагаемое время жизни Box<dyn Trait>. В параметрах метода нет времени жизни (исключенного или иного), из которого в любом случае можно было бы получить более короткое значение. Self могут иметь связанные с ним времена жизни, но они не могут повлиять на сигнатуру типажа, поэтому Self должен придерживаться ограничений типажа.

Это требует Sized из-за того, как реализованы объекты типа Box<dyn Trait>. Если у вас есть текст коробочного размера (Box<T>), то он представлен одним указателем. Если у вас есть упакованный неразмерный тип (Box<[T]>, Box<dyn Trait>, Box<str> и т. д.), то он представлен двумя указателями: один на значение, а другой на метаданные (v-таблица для объектов-характеристик или длина для срезов). Также известен как «толстый указатель».

Если бы Self не было Sized и вы попытались добавить к нему еще один уровень неразмерности, приведя его к Box<dyn Trait>, тогда либо это должен был бы быть «толстый толстый указатель», который был бы бессвязным, поскольку сам Box<dyn Trait> мог бы иметь два разных размера. , иначе придется потерять часть метаданных, чего, конечно, Rust не сделает.

См. Почему нельзя привести `&(?Sized + Trait)` к `&dyn Trait`? для более подробного объяснения.

Понятно, значит, размер &UnsizedType всегда будет больше, чем &SizedType, потому что первый возвращает толстый указатель, а второй возвращает обычный указатель?

user3929076 01.06.2024 05:47

@user3929076 user3929076 да, а это значит, что Box будет вести себя так же.

kmdreko 05.06.2024 01:17

Другие вопросы по теме