英文:
Clone custom structs of concrete type as trait objects
问题
使用Rc
,我可以将具体类型的Rc
转换为特征对象:
use std::rc::Rc;
trait Foo {}
impl Foo for usize {}
fn main() {
let x: Rc<usize> = Rc::new(1);
let y: Rc<dyn Foo> = x.clone();
}
如果我为Rc
定义一个没有Sized
边界的包装器,我也可以使用特征对象:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<dyn Foo> = Wrapper(Rc::new(1));
}
然而,我不能将具体类型的包装器克隆为特征对象:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = x.clone(); // 这不会编译
}
编译器报错如下:
error[E0308]: mismatched types
--> src/main.rs:13:31
|
13 | let y: Wrapper<dyn Foo> = x.clone();
| ---------------- ^^^^^^^^^ 预期特征对象 `dyn Foo`,找到 `usize`
| |
| 预期是由此引起的结构体 `Wrapper<dyn Foo>`
找到结构体 `Wrapper<usize>`
有关此错误的更多信息,请尝试运行 `rustc --explain E0308`。
error: 由于前一个错误,无法编译 `playground`
我有点困惑,因为我不理解为什么第三个示例不起作用。有人可以帮助我让第三个示例正常工作吗?我漏掉了什么?
英文:
Using Rc
, I can cast an Rc
of a concrete type to a trait object:
use std::rc::Rc;
trait Foo {}
impl Foo for usize {}
fn main() {
let x: Rc<usize> = Rc::new(1);
let y: Rc<dyn Foo> = x.clone();
}
If I define a wrapper for an Rc
without the Sized
bound, I can also use trait objects:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<dyn Foo> = Wrapper(Rc::new(1));
}
However, I cannot clone a wrapper of a concrete type as a trait object:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = x.clone(); // this does not compile
}
The compiler complains with the following error:
error[E0308]: mismatched types
--> src/main.rs:13:31
|
13 | let y: Wrapper<dyn Foo> = x.clone();
| ---------------- ^^^^^^^^^ expected trait object `dyn Foo`, found `usize`
| |
| expected due to this
|
= note: expected struct `Wrapper<dyn Foo>`
found struct `Wrapper<usize>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error
I'm a little bit confused, as I don't understand why the third example does not work. Can anyone help me to get the third example working? what am I missing?
答案1
得分: 0
这个其他示例可以工作:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = Wrapper(x.0.clone()); // 克隆内部的 Rc
}
虽然这对我来说足够了,但我认为它包含了太多样板代码。欢迎其他建议。
英文:
This other example works:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = Wrapper(x.0.clone()); // clone inner Rc
}
While it is enough for me, I think that it has too much boilerplate code. Other suggestions are welcome.
答案2
得分: 0
你可以通过为你的 Wrapper
实现 CoerceUnsized
来实现对不定大小类型的强制转换,示例代码如下:
#![feature(unsize, coerce_unsized)]
use std::ops::CoerceUnsized;
use std::marker::Unsize;
impl<U: ?Sized, T: Unsize<U>> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
然后,你最初使用的语法将会编译通过:
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = x.clone();
}
但由于你没有包含这个实现,编译器不知道你的类型可以被视为不定大小的。
注意:目前需要使用 unsize
和 coerce_unsized
特性,所以你必须使用 Nightly 编译器进行编译。
英文:
You can implement your own version of coercion to an unsized type by implementing CoerceUnsized
for your Wrapper
:
#![feature(unsize, coerce_unsized)]
use std::ops::CoerceUnsized;
use std::marker::Unsize;
impl<U: ?Sized, T: Unsize<U>> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
then the syntax you used initially does compile
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = x.clone();
}
But since you did not include that implementation the compiler doesn't know that your type can be unsized.
Note: Right now that requires the features unsize
and coerce_unsized
though so you have to compile with a nightly compiler.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论