【问题标题】:Access a field from a struct casted with Box<Trait>从使用 Box<Trait> 转换的结构中访问字段
【发布时间】:2015-04-11 22:17:00
【问题描述】:

我有以下代码,我认为这很不言自明。我面临的问题在于render 函数:

fn render(&self) -> &'static str {
    self.view.value
}

编译器抱怨的地方:

attempted access of field `view` on type `&Self`, but no field with that name was found`

完整代码:

struct View1 {
    value: &'static str,
}

struct View2 {
    value: &'static str,
    another_value: &'static str,
}

struct Pattern<T> {
    view: T,
}

trait Renderable {
    fn render(&self) -> &'static str {
        self.view.value
    }
}

impl <T> Renderable for Pattern <T> {}

fn patterns() -> Vec<Box<Renderable>> {
    vec![
        Box::new(Pattern { view: View1 { value: "x" } }),
        Box::new(Pattern { view: View1 { value: "y" } }),
    ]
}

fn main() {
    let p = patterns();

    for x in p.iter() {
        println!("{}", x.render());
    }
}

【问题讨论】:

    标签: rust


    【解决方案1】:

    是的,特征无法访问其实现者的字段。您需要提供访问器方法。这些都很小,应该优化掉:

    trait View {
        fn value(&self) -> &'static str;
    }
    
    struct View1 {
        value: &'static str,
    }
    
    impl View for View1 {
        fn value(&self) -> &'static str { self.value }
    }
    
    struct View2 {
        value: &'static str,
        another_value: &'static str,
    }
    
    impl View for View2 {
        fn value(&self) -> &'static str { self.value }
    }
    
    trait Renderable {
        fn view(&self) -> &View;
    
        fn render(&self) -> &'static str {
            self.view().value()
        }
    }
    
    struct Pattern<T>
        where T: View
    {
        view: T,
    }
    
    impl<T> Renderable for Pattern<T>
        where T: View
    {
        fn view(&self) -> &View {
            &self.view
        }
    }
    
    fn patterns() -> Vec<Box<Renderable>> {
        vec![
            Box::new(Pattern { view: View1 { value: "x" } }),
            Box::new(Pattern { view: View2 { value: "y", another_value: "z" } }),
        ]
    }
    
    fn main() {
        let p = patterns();
    
        for x in p.iter() {
            println!("{}", x.render());
        }
    }
    

    基本上,特征是对象必须遵守的契约,这些契约的语言是函数名称、参数类型和返回类型。如果一个 trait 需要能够获得 viewvalue,那么这需要成为 trait 的一部分。

    请注意,特征的实现 确实可以访问他们正在实现特征的结构的字段。由于实现是专门针对一种类型的,因此可以保证您可以访问相应的字段。

    【讨论】:

    • 这很棒。难道不能默认实现value() 方法吗?一遍又一遍地重复它们看起来很麻烦。
    • @caio 总是有宏! ^_^。但是,如果您确实发现自己一遍又一遍地重复代码,也许您可​​以将公共代码提取到一个新结构中,然后将该结构嵌入到您从中提取它的位置。否则,您将想要 不同的实现,因此默认值不会有用。您可能对this question 感兴趣,他询问了这两个极端之间的案例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多