无法找出一个函数来返回对存储在 RefCell<Box<Any>> 中的给定类型的引用. [英] Can&#39;t figure out a function to return a reference to a given type stored in RefCell&lt;Box&lt;Any&gt;&gt;

查看:39
本文介绍了无法找出一个函数来返回对存储在 RefCell<Box<Any>> 中的给定类型的引用.的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

其中大部分是样板文件,作为可编译示例提供.向下滚动.

Most of this is boilerplate, provided as a compilable example. Scroll down.

use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::any::{Any, AnyRefExt};

struct Shared {
    example: int,
}

struct Widget {
    parent: Option<Weak<Box<Widget>>>,
    specific: RefCell<Box<Any>>,
    shared: RefCell<Shared>,
}

impl Widget {
    fn new(specific: Box<Any>, 
           parent: Option<Rc<Box<Widget>>>) -> Rc<Box<Widget>> { 
        let parent_option = match parent {
            Some(parent) => Some(parent.downgrade()),
            None => None,
        };
        let shared = Shared{pos: 10};
        Rc::new(box Widget{
            parent: parent_option,
            specific: RefCell::new(specific),
            shared: RefCell::new(shared)})
    }
}

struct Woo {
    foo: int,
}

impl Woo {
    fn new() -> Box<Any> {
        box Woo{foo: 10} as Box<Any>
    }
}

fn main() {
    let widget = Widget::new(Woo::new(), None);

    {
        // This is a lot of work...
        let cell_borrow = widget.specific.borrow();
        let woo = cell_borrow.downcast_ref::<Woo>().unwrap();
        println!("{}", woo.foo);
    }

    // Can the above be made into a function?
    // let woo = widget.get_specific::<Woo>();
}

我正在学习 Rust 并试图找出一些可行的方法来制作小部件层次结构.上面基本上做了我需要的,但是有点麻烦.尤其令人烦恼的是,我必须使用两个语句来转换内部小部件(Widgetspecific 成员).我尝试了多种方法来编写一个功能齐全的函数,但引用的数量和生命周期的魔法超出了我的能力.

I'm learning Rust and trying to figure out some workable way of doing a widget hierarchy. The above basically does what I need, but it is a bit cumbersome. Especially vexing is the fact that I have to use two statements to convert the inner widget (specific member of Widget). I tried several ways of writing a function that does it all, but the amount of reference and lifetime wizardry is just beyond me.

能做到吗?我的示例代码底部注释掉的方法能否实现?

感谢有关更好地完成整件事的评论,但请将其放在评论部分(或创建一个新问题并链接)

Comments regarding better ways of doing this entire thing are appreciated, but put it in the comments section (or create a new question and link it)

推荐答案

我将展示您的代码的工作简化和更惯用的版本,然后解释我在那里所做的所有更改:

I'll just present a working simplified and more idiomatic version of your code and then explain all the changed I made there:

use std::rc::{Rc, Weak};
use std::any::{Any, AnyRefExt};

struct Shared {
    example: int,
}

struct Widget {
    parent: Option<Weak<Widget>>,
    specific: Box<Any>,
    shared: Shared,
}

impl Widget {
    fn new(specific: Box<Any>, parent: Option<Rc<Widget>>) -> Widget { 
        let parent_option = match parent {
            Some(parent) => Some(parent.downgrade()),
            None => None,
        };
        let shared = Shared { example: 10 };
        Widget{
            parent: parent_option,
            specific: specific,
            shared: shared
        }
    }

    fn get_specific<T: 'static>(&self) -> Option<&T> {
        self.specific.downcast_ref::<T>()
    }
}

struct Woo {
    foo: int,
}

impl Woo {
    fn new() -> Woo {
        Woo { foo: 10 }
    }
}

fn main() {
    let widget = Widget::new(box Woo::new() as Box<Any>, None);

    let specific = widget.get_specific::<Woo>().unwrap();
    println!("{}", specific.foo);
}

首先,您的结构中有不必要的RefCell.RefCell 很少需要 - 仅当您需要仅使用 & 引用(而不是 &mut)来改变对象的内部状态时).这是实现抽象的有用工具,但在应用程序代码中几乎不需要它.因为从您的代码中不清楚您真的需要它,所以我假设它被错误地使用并且可以被删除.

First of all, there are needless RefCells inside your structure. RefCells are needed very rarely - only when you need to mutate internal state of an object using only & reference (instead of &mut). This is useful tool for implementing abstractions, but it is almost never needed in application code. Because it is not clear from your code that you really need it, I assume that it was used mistakingly and can be removed.

接下来, Rc>Something 是一个结构体时(就像在你的情况下 Something = Widget) 是多余的.将拥有的框放入引用计数的框只是不必要的双重间接和分配.简单的 Rc 是表达这个东西的正确方式.当动态大小的类型登陆时,特征对象也是如此.

Next, Rc<Box<Something>> when Something is a struct (like in your case where Something = Widget) is redundant. Putting an owned box into a reference-counted box is just an unnecessary double indirection and allocation. Plain Rc<Widget> is the correct way to express this thing. When dynamically sized types land, it will be also true for trait objects.

最后,您应该尝试始终返回未装箱的值.返回 Rc>(甚至 Rc)对于代码的调用者来说是不必要的限制.您可以轻松地从 Widget 转到 Rc,但不能反过来.Rust 自动优化按值返回;如果您的调用者需要 Rc,他们可以自己装箱返回值:

Finally, you should try to always return unboxed values. Returning Rc<Box<Widget>> (or even Rc<Widget>) is unnecessary limiting for the callers of your code. You can go from Widget to Rc<Widget> easily, but not the other way around. Rust optimizes by-value returns automatically; if your callers need Rc<Widget> they can box the return value themselves:

let rc_w = box(RC) Widget::new(...);

对于 Woo::new() 返回的 Box 也是如此.

Same thing is also true for Box<Any> returned by Woo::new().

您可以看到,在没有 RefCell 的情况下,您的 get_specific() 方法可以很容易地实现.但是,您确实无法使用 RefCell 来实现,因为 RefCell 使用 RAII 进行动态借用检查,因此您无法从方法返回对其内部的引用.您必须返回 core::cell::Refs,并且您的调用者需要自己downcast_ref().这只是谨慎使用 RefCell 的另一个原因.

You can see that in the absence of RefCells your get_specific() method can be implemented very easily. However, you really can't do it with RefCell because RefCell uses RAII for dynamic borrow checks, so you can't return a reference to its internals from a method. You'll have to return core::cell::Refs, and your callers will need to downcast_ref() themselves. This is just another reason to use RefCells sparingly.

这篇关于无法找出一个函数来返回对存储在 RefCell<Box<Any>> 中的给定类型的引用.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆