我一直在用 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,但我看不出它们如何适用于我的案例(如果它们确实适用的话)。
问题是你的
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();
}