Rust Trait对象转换

时间:2017-01-12 02:22:06

标签: rust type-conversion traits coercion

由于此错误的两个实例,以下代码将无法编译:

  

错误[E0277]:不满足特征限制Self: std::marker::Sized

我不明白为什么在这个实例中需要Sized,因为&self&Any都是指针,并且操作不需要知道实现该实现的结构的大小trait,它只需要知道指针本身及其转换的类型,因为&self在特征中实现时是通用的。

我认为这可能是编译器强制执行不必要约束的一个实例,我考虑过使用生锈的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()所需的函数,但对于这些结构,实现将始终与此处显示的每个字符完全相同,导致几个相同的样板代码实例。

2 个答案:

答案 0 :(得分:6)

动态大小的类型也可以实现特征。特别是,当您定义对象安全特征时,编译器还会定义一个动态大小的类型,其名称与特征相同,这样您就可以使用&Component等对象类型。

&Component&Any等对象类型不仅仅是普通指针;他们是胖指针。胖指针结合了指向数据的指针和另一个数据:对于对象类型,它是指向vtable的指针;对于切片,它是切片的长度。

当从常规指针(例如&Button)转换为对象类型时,编译器静态地知道将哪个vtable放入胖指针(例如Button的{​​{1}}的vtable })。另一方面,Rust不支持从对象类型转换为另一种对象类型(例如从Any&Component),因为对象中没有足够的数据来初始化新的胖指针。这就是编译器将此注释添加到错误消息中的原因:

&Any

有两种方法可以解决这个问题:

  1. 要求实施= note: required for the cast to the object type `std::any::Any + 'static` 的所有类型都为Component

    Sized

    这导致您无法使用trait Component: Any + Sized { fn as_any(&self) -> &Any { self } fn as_any_mut(&mut self) -> &mut Any { self } } &Component等对象类型。

  2. 仅当Box<Component>as_any时,as_any_mutSelf方法才可用:

    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

答案 1 :(得分: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?的想法。