2017-01-12 14 views
3

Следующий код не будет компилироваться из-за двух экземпляров этой ошибки:Rust Черта преобразования объекта

error[E0277]: the trait bound Self: std::marker::Sized is not satisfied

Я не понимаю, почему Sized требуется в данном случае, и как &self и &Any являются указателями, и операция не требует знания размера структуры, которая реализует признак, она требует только знания самого указателя и типа, из которого он преобразуется, и который он будет иметь, поскольку &self является общим, когда он реализован внутри признака.

Я думаю, что это может быть экземпляр компилятора, принуждающего к ненужным ограничениям, и я рассмотрел вопрос о проблеме с репозиторией Rust-lang GitHub, но я подумал, что, вероятно, я должен увидеть, знает ли кто-то, что я чего-то не делаю до того, как я Пойдите, файл, проблема.

use std::any::Any; 

trait Component: Any { 
    fn as_any(&self) -> &Any { 
     self 
    } 

    fn as_any_mut(&mut self) -> &mut Any { 
     self 
    } 
} 

Альтернатива это сделать as_any() и as_any_mut() необходимых функций для структур, которые реализуют эту черту, но и для тех структур, реализация всегда будет точно, как показано здесь, вплоть до каждого индивидуального характера, в результате чего в ряде случаев идентичного шаблона.

+0

Я удалил свой ответ, потому что я не могу найти ссылку на документацию достаточно быстро. Однако я понимаю, что 'Self' в чертах не имеет значения и без явной маркировки вашей черты как' Sized' компилятор увидит ее как unsized и error. –

+1

Я думаю, что создание необходимых методов - это путь. По крайней мере, я видел эту модель раньше. Чтобы избежать дублирования кода, вы можете написать простой макрос 'impl_conversion_functions!()' Или что-то в этом роде. –

ответ

6

Динамически размерные типы также могут реализовывать черты. В частности, когда вы определяете объектно-безопасный признак, компилятор также определяет тип динамического размера с тем же именем, что и признак, который позволяет использовать типы объектов, такие как &Component.

Объекты, такие как &Component или &Any, являются не только обычными указателями; они указатели жира. Толстый указатель объединяет указатель на данные и другую часть данных: для типов объектов это указатель на vtable; для срезов это длина среза.

При литье от обычного указателя (например, &Button) к типу объекта, компилятор статически знает, какие виртуальные таблицы поместить в указатель жира (например, виртуальные таблицы Button «ы для Any). С другой стороны, Rust не поддерживает отливку от типа объекта к другому типу объекта (например, от &Component до &Any), поскольку в объекте недостаточно данных для инициализации нового указателя жира. Поэтому компилятор добавляет эту ноту к сообщению об ошибке:

= note: required for the cast to the object type `std::any::Any + 'static` 

Есть два способа исправить это:

  1. Требуют, что все виды реализации Component быть Sized:

    trait Component: Any + Sized { 
        fn as_any(&self) -> &Any { 
         self 
        } 
    
        fn as_any_mut(&mut self) -> &mut Any { 
         self 
        } 
    } 
    

    Это приводит к тому, что вы не сможете использовать типы объектов, такие как &Component или Box<Component>.

  2. Сделать методы as_any и as_any_mut доступны только тогда, когда Self является Sized:

    trait Component: Any { 
        fn as_any(&self) -> &Any 
         where Self: Sized 
        { 
         self 
        } 
    
        fn as_any_mut(&mut self) -> &mut Any 
         where Self: Sized 
        { 
         self 
        } 
    } 
    

    Таким образом, вы все еще можете использовать типы объектов для признака, но вы не сможете позвонить as_any и as_any_mut на их.

+0

Это имеет смысл. К сожалению, для моей конкретной ситуации мне нужно иметь возможность вызывать эти функции на объектах признаков. Я посмотрю, смогу ли я найти другой способ –

4

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

pub trait Component { 
    // ... 
} 

pub trait ComponentAny: Component + Any { 
    fn as_any(&self) -> &Any; 
    fn as_any_mut(&mut self) -> &mut Any; 
} 

impl<T> ComponentAny for T 
    where T: Component + Any 
{ 
    fn as_any(&self) -> &Any { 
     self 
    } 

    fn as_any_mut(&mut self) -> &mut Any { 
     self 
    } 
} 

Отсюда, я просто изменить весь свой API, чтобы принять ComponentAny вместо Component. Поскольку Any автоматически применяется для любого типа 'static, ComponentAny теперь автоматически применяется для любого типа 'static, который реализует Component. Благодаря идее Is there a way to combine multiple traits in order to define a new trait?.

 Смежные вопросы

  • Нет связанных вопросов^_^