rust 中的 'core::kinds::Sized` is not implemented for the type `Self' 是什么?
What is 'core::kinds::Sized` is not implemented for the type `Self' in 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 error: the trait core::kinds::Sized
is not implemented for the type Self
:15 return Foo::new(self);
我能猜出哪里出了问题;它是说我的 Foo<'a, T> 是针对 T,而不是 Sized 的? T,但我不是要存储 Sized?其中的元素;我将 reference 存储到其中的 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 and #20341 允许例如impl Array<T> for Array<T>
默认情况下更频繁地工作(我们稍后会谈到)。
变量 self
的类型为 &Self
。如果 Self
是大小类型,那么这是一个普通引用:一个指针。如果 Self
是未确定大小的类型(如 [T]
或特征),则 &Self
(&[T]
或 &Trait
)是 slice/trait 对象:一个胖指针。
错误出现是因为唯一可以转换为特征对象的引用&T
是在T
大小时: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。)
回到绘图板。还有其他一些 "easy" 可能的解决方案:
- 定义扩展特征
trait ArrayExt: Sized + Array { fn as_foo(&self) { ... } }
并为所有 Sized + Array
类型实现它
- 只需使用一个免费功能
fn array_as_foo<A: Array>(x: &A) { ... }
但是,这些不一定适用于每个用例,例如特定类型无法通过重载默认方法来自定义行为。然而,幸运的是有一个修复!
Turon 把戏
(以发现它的 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) 强制转换是合法的,因为 Self
是 Sized
所以 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 in the near future: first one 上。)
这曾经有效:
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 typeSelf
:15 return Foo::new(self);
我能猜出哪里出了问题;它是说我的 Foo<'a, T> 是针对 T,而不是 Sized 的? T,但我不是要存储 Sized?其中的元素;我将 reference 存储到其中的 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 and #20341 允许例如impl Array<T> for Array<T>
默认情况下更频繁地工作(我们稍后会谈到)。
变量 self
的类型为 &Self
。如果 Self
是大小类型,那么这是一个普通引用:一个指针。如果 Self
是未确定大小的类型(如 [T]
或特征),则 &Self
(&[T]
或 &Trait
)是 slice/trait 对象:一个胖指针。
错误出现是因为唯一可以转换为特征对象的引用&T
是在T
大小时: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。)
回到绘图板。还有其他一些 "easy" 可能的解决方案:
- 定义扩展特征
trait ArrayExt: Sized + Array { fn as_foo(&self) { ... } }
并为所有Sized + Array
类型实现它 - 只需使用一个免费功能
fn array_as_foo<A: Array>(x: &A) { ... }
但是,这些不一定适用于每个用例,例如特定类型无法通过重载默认方法来自定义行为。然而,幸运的是有一个修复!
Turon 把戏
(以发现它的 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) 强制转换是合法的,因为 Self
是 Sized
所以 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 in the near future: first one 上。)