首页 文章

什么是'core::kinds::Sized` is not implemented for the type `Self'生锈?

提问于
浏览
9

这曾经工作:

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错误:特征核心::种类::大小不是为Self类型实现的:15返回Foo :: new(self);

我可以猜到's wrong; it'是什么意思说我的Foo <'a, T> is for T, not Sized? T, but I' m不要试图存储大小?其中的元素;我正在存储对Sized元素的引用 . 那应该是一个固定大小的指针 .

我不知道我在做什么,或者为什么这是错的?

例如,我应该(我认为......)能够在我的Foo中存储一个&Array,没问题 . 我看不出有什么理由会强迫我的Foo实例被取消 .

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

1 回答

  • 14

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

    错误

    正如错误消息所暗示的那样,代码的难点部分是 Foo::new(self) ,这是因为 pub fn new<T>(parent: &Array<T>) -> ... ,即 self 被强制转换为 &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 可能是未标注的( ?Sized ),因为RFC 546#20341用于允许例如 impl Array<T> for Array<T> 默认更频繁地工作(我们稍后会讨论) .

    变量 self 的类型为 &Self . 如果 Self 是一个大小的类型,那么这是一个普通的引用:一个指针 . 如果 Self 是未大小的类型(如 [T] 或特征),则 &Self&[T]&Trait )是切片/特征对象:胖指针 .

    出现错误是因为可以强制转换为特征对象的唯一引用 &TT 的大小:Rust不知道 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() {}
    

    看起来不错!

    除了工作之外的其他工作;但至少它正在取得进展!特质对象只能由"object safe"的特征组成(即可以安全地制作特征对象),并且 Sized Self 是破坏对象安全的事情之一:

    <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
                         ^~~~
    

    (我将该笔记的双重打印作为#20692提交 . )

    回到绘图板 . 解决方案还有其他一些“简单”的可能性:

    • 定义扩展特征 trait ArrayExt: Sized + Array { fn as_foo(&self) { ... } } 并为所有 Sized + Array 类型实现它

    • 只需使用免费功能 fn array_as_foo<A: Array>(x: &A) { ... }

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

    Turon Trick

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

    使用广义 where 子句,我们可以高度具体地说明 Self 何时应该实现 Sized ,将其限制为只需要它的方法,而不会感染其余的特征:

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

    编译得很好!通过使用像这样的 where 子句,编译器理解(a)强制是合法的,因为 SelfSized 所以 self 是一个瘦指针,并且(b)该方法无论如何都要调用特征对象是非法的,所以不会打破物体安全 . 要查看它被禁止,请将 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() {
    }
    

    编译没有错误 . (注意:我必须删除 pub fn new<T> 中不必要的 <T> ,因为这会导致推理失败 . )

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

相关问题