【问题标题】:Why sized trait is required for a builder function to generate Rc<T>?为什么生成器函数需要大小特征来生成 Rc<T>?
【发布时间】:2019-03-08 10:52:33
【问题描述】:

此代码运行良好 (playground):

use std::rc::Rc;

trait Foo {
    fn foo(&self);
}

struct Bar<T> {
    v: Rc<T>,
}

impl<T> Bar<T> where
T: Foo {
    fn new(rhs: Rc<T>) -> Bar<T> {
        Bar{v: rhs}
    }
}

struct Zzz {
}

impl Zzz {
    fn new() -> Zzz {
        Zzz{}
    }
}

impl Foo for Zzz {
    fn foo(&self) {
        println!("Zzz foo");
    }
}

fn make_foo() -> Rc<Foo> {
    Rc::new(Zzz{})
}

fn main() {
    let a = Bar::new(Rc::new(Zzz::new()));
    a.v.as_ref().foo()
}

但是如果我像下面那样制作一个包装器来生成 Rc,编译器会抱怨缺少大小特征 (playground)

fn make_foo() -> Rc<dyn Foo> {
    Rc::new(Zzz::new())
}

fn main() {
    let a = Bar::new(make_foo());
    a.v.as_ref().foo()
}

在这两种情况下,Bar::new 都接收到具有相同类型 Rc 的参数,为什么 rust 编译器的反应不同?

【问题讨论】:

标签: rust traits smart-pointers trait-objects


【解决方案1】:

默认情况下,所有类型变量都假定为Sized。例如,在Bar 结构的定义中,有一个隐含的Sized 约束,像这样:

struct Bar<T: Sized> {
    v: Rc<T>,
}

对象dyn Foo 不能Sized,因为Foo 的每个可能实现都可能有不同的大小,所以没有一个可以选择的大小。但是您正在尝试实例化 Bar&lt;dyn Foo&gt;

解决方法是为 T 选择退出 Sized 特征:

struct Bar<T: ?Sized> {
    v: Rc<T>,
}

而且在实现的上下文中:

impl<T: ?Sized> Bar<T>
where 
    T: Foo 

?Sized其实并不是一个约束,而是放宽了现有的Sized约束,这样就不需要了。

选择退出 Sized 的后果是,Bar 的任何方法都不能使用 impl 块,除非通过引用。

【讨论】:

    猜你喜欢
    • 2017-11-18
    • 2021-04-27
    • 1970-01-01
    • 2016-09-06
    • 2011-09-20
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    相关资源
    最近更新 更多