我应该在 Rust 中尽可能避免使用 Rc 和 RefCell 吗?

Kid*_*nbo 4 rust

Rust 在编译时提供借用检查。但如果使用Rcand RefCell,检查将在运行时推迟,并且当程序违反规则时将引发恐慌。像这样:

use std::rc::Rc;
use std::cell::RefCell;

fn func1(reference: Rc<RefCell<String>>){
    let mut a = reference.borrow_mut();
    *a = String::from("func1");
    func2(reference.clone());
}

fn func2(reference: Rc<RefCell<String>>){
    let mut a = reference.borrow_mut();
    *a = String::from("func2");
    func3(reference.clone());
}

fn func3(reference: Rc<RefCell<String>>){
    let mut a = reference.borrow_mut();
    *a = String::from("func3");
}


fn main() {
    let a = Rc::new(RefCell::new(String::from("hello")));
    func1(a.clone());
}

Run Code Online (Sandbox Code Playgroud)

这段代码仍然将错误(也许不是错误)留给运行时并陷入恐慌。那么我应该尽可能避免使用Rcand吗?RefCell这段代码算安全代码吗?

Bil*_*ket 5

由于RcRefCell允许您编译在运行时可能会出现恐慌的代码,因此不要轻易使用它们。您可以使用try_borrow_mut而不是borrow_mut避免恐慌并自己处理结果。

话虽这么说,即使您防止了所有恐慌,Rc并且RefCell在运行时会产生成本,因为它们保留了引用计数器。在许多情况下,您可以通过以更生疏的方式重写代码来避免它们。

fn func1(mut string: String) -> String {
    string = "func1".into();
    func2(string)
}

fn func2(mut string: String) -> String {
    string = "func2".into();
    func3(string)
}

fn func3(string: String) -> String {
    "func3".into()
}

fn main() {
    let a = func1("hello".into());
}

Run Code Online (Sandbox Code Playgroud)

更简单,更安全。Rust 会为你进行优化。

要回答你的最后一个问题,使用borrow_mut不被视为不安全代码,因为即使使用#![forbid(unsafe_code)]指令代码也可以编译