gpt4 book ai didi

rust - 什么是 'core::kinds::Sized` 没有为 rust 中的 `Self' 类型实现?

转载 作者:行者123 更新时间:2023-11-29 07:44:23 25 4
gpt4 key购买 nike

这曾经有效:

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 error: the trait core::kinds::Sized is not implemented for the type Self :15 return Foo::new(self);



我可以猜出什么是错的;是说我对 Foo<'a, T> 的 impl 是针对 T,而不是 Sized? T,但我不想存储 Sized?其中的元素;我在其中存储了对 Sized 元素的引用。那应该是一个指针,固定大小。

我看不出我在做什么有什么问题,或者为什么它是错的?

例如,我应该(我认为......)能够在我的 Foo 中存储一个 &Array,没问题。我看不出有任何原因会迫使我的 Foo 实例变小。

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

最佳答案

这里发生了两件事:特征对象强制(错误)和对象安全(修复它)。

错误

正如错误消息所暗示的,代码的困难部分是 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 )是一个切片/特征对象:一个胖指针。

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

修复它

我们正在寻找的解决方法是确保 Self: Sized当我们想做强制时。这样做的明显方法是使 Self总是 Sized ,即覆盖默认的 ?Sized绑定(bind)如下:
trait Array: Sized {
fn as_foo(&self) {
let _ = self as &Array; // coerce to a trait object
}
}

fn main() {}

看起来挺好的!

除了它不起作用的小点。但至少这是出于不同的原因,我们正在取得进展!特征对象只能由“对象安全”(即可以安全地制作为特征对象)的特征制成,并且具有 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) { ... }

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

    特隆把戏

    (以发现它的 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) 无论如何调用 trait 对象的方法都是非法的,因此不会破坏对象的安全性。要看到它被禁止,更改 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> 中不必要的 pub fn new<T>,因为这会导致推理失败。)

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

    关于rust - 什么是 'core::kinds::Sized` 没有为 rust 中的 `Self' 类型实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27816023/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com