Jos*_*ada 6 rust trait-objects
我正在研究一些 API 概念,并注意到 Rust 的 Iterator 特性中有一些特殊之处。
我有以下特征定义:
trait Observable {
type Item;
fn subscribe<F>(self, f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) + 'static;
}
Run Code Online (Sandbox Code Playgroud)
然后我继续编写以下测试:
#[test]
#[should_panic]
fn trait_obj() {
let mut v: Vec<Box<dyn Iterator<Item = ()>>> = vec![];
let mut v2: Vec<Box<dyn Observable<Item = Ref<u8>>>> = vec![];
v.remove(0).for_each(|_| {});
v2.remove(0).subscribe(|_| {});
}
Run Code Online (Sandbox Code Playgroud)
正如人们所期望的那样,上述测试无法编译;subscribe()按值获取 self,并且对 具有Sized约束Self,因此不是对象安全的。但是,如果我注释掉该...subscribe行,它就会编译!
对我来说奇怪的是,Iterator::for_each()有相同的限制。为什么允许这样做Iterator而不是允许这样做Observable?这是一个实验性的功能吗?
Iterator::for_each这是供参考的函数签名:
// Iterator::for_each
fn for_each<F>(self, f: F)
where
Self: Sized,
F: FnMut(Self::Item);
Run Code Online (Sandbox Code Playgroud)
Iterator::for_each和的函数签名Observable::subscribe几乎相同。
是什么赋予了?
你的错误在于你认为你打电话了<dyn Iterator<Item = ()>>::for_each(),然后你理所当然地想知道如果for_each()需要Self: Sized但dyn Iterator<Item = ()>显然不是的话你该如何做Sized。但你错了。您可以看到,如果您使用 UFCS(通用函数调用语法):
#[test]
#[should_panic]
fn trait_obj() {
let mut v: Vec<Box<dyn Iterator<Item = ()>>> = vec![];
// v.remove(0).for_each(|_| {});
<dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
}
Run Code Online (Sandbox Code Playgroud)
游乐场。
发出:
error[E0277]: the size for values of type `dyn Iterator<Item = ()>` cannot be known at compilation time
--> src/lib.rs:7:5
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = ()>`
note: required by a bound in `for_each`
error[E0308]: mismatched types
--> src/lib.rs:7:41
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^ expected trait object `dyn Iterator`, found struct `Box`
|
= note: expected trait object `dyn Iterator<Item = ()>`
found struct `Box<dyn Iterator<Item = ()>>`
help: consider unboxing the value
|
7 | <dyn Iterator<Item = ()>>::for_each(*v.remove(0), |_| {});
| +
error[E0277]: the size for values of type `dyn Iterator<Item = ()>` cannot be known at compilation time
--> src/lib.rs:7:41
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = ()>`
= note: all function arguments must have a statically known size
Run Code Online (Sandbox Code Playgroud)
这个错误还提示您为什么以前的版本有效:您没有调用<dyn Iterator<Item = ()>>::for_each(),您调用了Box::<dyn Iterator<Item = ()>>::for_each()!Box<Iterator>实现了Iterator它自己,所以它起作用了。您可以在 MIR 中明确地看到这一点:
error[E0277]: the size for values of type `dyn Iterator<Item = ()>` cannot be known at compilation time
--> src/lib.rs:7:5
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = ()>`
note: required by a bound in `for_each`
error[E0308]: mismatched types
--> src/lib.rs:7:41
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^ expected trait object `dyn Iterator`, found struct `Box`
|
= note: expected trait object `dyn Iterator<Item = ()>`
found struct `Box<dyn Iterator<Item = ()>>`
help: consider unboxing the value
|
7 | <dyn Iterator<Item = ()>>::for_each(*v.remove(0), |_| {});
| +
error[E0277]: the size for values of type `dyn Iterator<Item = ()>` cannot be known at compilation time
--> src/lib.rs:7:41
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = ()>`
= note: all function arguments must have a statically known size
Run Code Online (Sandbox Code Playgroud)
// Snip
_2 = <Box<dyn Iterator<Item = ()>> as Iterator>::for_each::<[closure@src/lib.rs:4:26: 4:32]>(move _3, move _5) -> [return: bb3, unwind: bb5];
// Snip
Run Code Online (Sandbox Code Playgroud)
游乐场(从菜单中选择“显示 MIR”)。
如果您已经实施过Observable,Box<O> where O: Observable它也会对您有用......
...除非你不能。因为您无法将呼叫转接至for_each()。它使用的原因Iterator是它不转发此调用,而是使用一次又一次调用的默认实现next()。因为next()需要&mut self,所以不需要Self: Sized。
| 归档时间: |
|
| 查看次数: |
574 次 |
| 最近记录: |