什么是'core :: types :: Sized`没有实现类型`Self'在生锈?

时间:2015-01-07 09:20:17

标签: rust

这曾经有用:

struct Foo<'a, T> {
  parent:&'a (Array<T> + 'a)
}

impl<'a, T> Foo<'a, T> { //'
  pub fn new<T>(parent:&Array<T>) -> Foo<T> {
    return Foo {
      parent: parent
    };
  }
}

trait Array<T> {
  fn as_foo(&self) -> Foo<T> {
    return Foo::new(self);
  }
}

fn main() {
}

现在错误:

  

:15:21:15:25错误:core::kinds::Sized类型没有实现特征Self   :15返回Foo :: new(self);

我可以猜出错了什么;它说我的Foo&lt;&#39; a,T&gt;是T,不是大小? T,但我没有尝试存储尺寸?其中的元素;我将引用存储到其中的Sized元素中。那应该是一个固定大小的指针。

我不知道自己在做什么,或者为什么会出错?

例如,我应该(我认为......)能够在我的Foo中存储&amp;数组,没问题。我无法理解这会导致我的Foo实例无法使用。

围栏链接:http://is.gd/eZSZYv

1 个答案:

答案 0 :(得分:14)

这里有两件事:特质对象强制(错误)和对象安全(修复它)。

错误

根据错误消息的建议,代码的难点部分是Foo::new(self),这是因为pub fn new<T>(parent: &Array<T>) -> ...,即self被强制转换为{{1}特质对象。我将代码简化为:

&Array<T>

给出了相同的东西:

trait Array {
  fn as_foo(&self) {
    let _ = self as &Array; // coerce to a trait object
  }
}

fn main() {}

<anon>:3:13: 3:27 error: the trait `core::kinds::Sized` is not implemented for the type `Self` <anon>:3 let _ = self as &Array; // coerce to a trait object ^~~~~~~~~~~~~~ 是实现特征的类型的替代名称。与大多数通用参数不同,默认情况下Self可能未归档(Self),因为RFC 546#20341用于允许,例如?Sized默认更频繁地工作(我们稍后会讨论这个问题)。

变量impl Array<T> for Array<T>的类型为self。如果&Self是一个大小的类型,那么这是一个普通的引用:一个指针。如果Self是未归类的类型(如Self或特征),则[T]&Self&[T])是切片/特征对象:脂肪指针。

出现错误是因为可以强制转换为特征对象的唯一引用&Trait&T的大小:Rust不支持使胖指针更胖,只有瘦指针→胖指针有效。因此,由于编译器不会知道 T始终为Self(请记住,它是特殊的,默认为Sized)它必须承担最坏的情况:强制是不合法的,所以它是不允许的。

修复它

我们正在寻找的解决方案似乎是合乎逻辑的,以便在我们想要强制执行时确保?Sized。显而易见的方法是使Self: Sized 始终 Self,即覆盖默认的Sized界限,如下所示:

?Sized

看起来不错!

除了它没有用的小点之外;但至少出于不同的原因,我们正在取得进展!特质对象只能由对象安全的特征组成。 (即安全地被制成特质对象),trait Array: Sized { fn as_foo(&self) { let _ = self as &Array; // coerce to a trait object } } fn main() {} Sized是打破对象安全的事情之一:

Self

(我将该备注的双重打印归档为#20692。)

回到绘图板。还有其他一些&#34; easy&#34;解决方案的可能性:

  • 定义扩展特征<anon>:3:13: 3:17 error: cannot convert to a trait object because trait `Array` is not object-safe [E0038] <anon>:3 let _ = self as &Array; // coerce to a trait object ^~~~ <anon>:3:13: 3:17 note: the trait cannot require that `Self : Sized` <anon>:3 let _ = self as &Array; // coerce to a trait object ^~~~ <anon>:3:13: 3:17 note: the trait cannot require that `Self : Sized` <anon>:3 let _ = self as &Array; // coerce to a trait object ^~~~ 并为所有trait ArrayExt: Sized + Array { fn as_foo(&self) { ... } }类型
  • 实施
  • 只需使用免费功能Sized + Array

但是,这些并不一定适用于每个用例,例如:特定类型无法通过重载默认方法来自定义行为。但是,幸运的是有一个修复!

Turon Trick

(以发现它的Aaron Turon命名。)

使用广义fn array_as_foo<A: Array>(x: &A) { ... }条款,我们可以高度具体地说明where何时应该实现Self,将其限制为只需要它的方法,而不会影响其余的特点:

Sized

这个编译得很好!通过使用这样的trait Array { fn as_foo(&self) where Self: Sized { let _ = self as &Array; // coerce to a trait object } } fn main() {} 子句,编译器理解(a)强制是合法的,因为whereSelf所以Sized是一个瘦指针,(b)该方法无论如何都要调用特征对象是非法的,因此不会破坏对象的安全性。要查看它被禁止,请将self的正文更改为

as_foo

给出

let x = self as &Array; // coerce to a trait object
x.as_foo();

正如所料。

全部包装

对原始的未简化代码进行此更改非常简单,将<anon>:4:7: 4:15 error: the trait `core::kinds::Sized` is not implemented for the type `Array` <anon>:4 x.as_foo(); ^~~~~~~~ 子句添加到where方法:

as_foo

编译没有错误。 (注意:我必须删除struct Foo<'a, T> { //' parent:&'a (Array<T> + 'a) } impl<'a, T> Foo<'a, T> { pub fn new(parent:&Array<T>) -> Foo<T> { return Foo { parent: parent }; } } trait Array<T> { fn as_foo(&self) -> Foo<T> where Self: Sized { return Foo::new(self); } } fn main() { } 中不必要的<T>,因为这会导致推理失败。)

(我的一些正在进行的博客文章涉及特质对象,对象安全和Turon技巧,它们将在不久的将来出现在/r/rust上:first one。)