无法借用“Rc”中的可变数据

问题描述 投票:0回答:1

我一直在用 Rust 编写光线追踪器,但遇到了一个问题。我定义了以下结构:

pub struct HitRecord{
     mat : Rc<RefCell<dyn Material>,
     ...
}

Material
特质只有一个相关功能:

pub trait Material{
fn scatter(&mut self,r_in : &mut Ray, rec : &HitRecord, attenuation : &mut Color, scattered : &mut Ray) -> bool; 
}

某些结构(例如

Lambertian
Metal
)实现。我不明白我应该如何从另一段代码中调用这个函数:

    let mut rec : HitRecord = HitRecord::new(); 

    if world.hit(r, &mut Interval{min : 0.001, max : INFINITY} , &mut rec){
        let mut scattered = Ray::new();
        let mut attenuation = Color::new();
        let temp = rec.mat.clone();

        if temp.scatter(r, &rec, &mut attenuation,&mut scattered) {
            return attenuation * self.ray_color(&mut scattered,depth-1,world);
        }   

        return Color::new();
    }

函数调用

world.hit()
要求
rec
是可变的,因为它分配给它。问题出现在第二个if语句中:

error[E0596]: cannot borrow data in an `Rc` as mutable
--> camera.rs:128:16
|
|             if temp.get_mut().scatter(r, &rec, &mut attenuation,&mut scattered) {
|                ^^^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<RefCell<dyn material::Material>>`

我尝试为

DerefMut
实现
dyn Material
,但我收到了关于
Deref
不满意以及在实现各种其他错误时遇到的不同错误;我无法正确实施它。我也尝试过将
Rc<RefCell>
与其他东西切换,例如
Rc
Box
Rc<Box>
等等,但没有结果。我搜索了带有类似错误消息的questions,但我看不出它们如何适用于我的案例(如果它们确实适用的话)。

rust borrow-checker dereference raytracing
1个回答
0
投票

问题是你的

get_mut
没有意义:
get_mut
的目的是当你有一个对 refcell 的可变引用时简单地提供一个对包装值的可变引用。

但是你没有这个,

Rc

只会分发共享参考(除非你使用
Rc::get_mut
并且它是唯一突出的参考,但它不是正常使用)。

从 RefCell 获取可变引用的正常方法是

borrow_mut

,它在运行时检查是否没有未完成的借用(可变或不可变),然后返回一个。您甚至不需要克隆 
rec.mat
,除非您需要存储新实例。

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8801c8388486b54739bbc8ffe14bc1c8

use std::cell::RefCell; use std::rc::Rc; struct Stone; trait Material { fn scatter(&mut self) { println!("scattering"); } } impl Material for Stone {} fn main() { let f = Rc::new(RefCell::new(Stone)) as Rc<RefCell<dyn Material>>; f.borrow_mut().scatter(); }
    
© www.soinside.com 2019 - 2024. All rights reserved.