【发布时间】:2015-05-02 15:36:44
【问题描述】:
为了理解 Rust,我正在尝试实现一个小公式解释器。
表达式只能是整数、总和、变量 (Term) 或赋值 (Set)。然后我们可以评估一个表达式。由于没有关联值的符号可以出现在表达式中,因此它的求值会产生另一个表达式(不一定是整数)。
变量的值(如果有的话)可以在哈希表中找到。
use std::rc::Rc;
use std::collections::HashMap;
enum Expr {
Integer(i32),
Term(String),
Plus(Rc<Expr>, Rc<Expr>),
Set(Rc<Expr>, Rc<Expr>),
}
impl Expr {
fn evaluate(&self, env: &mut HashMap<String, Expr>) -> Expr {
match *self {
Expr::Plus(ref a, ref b) => {
let a_ev = Rc::new(a.evaluate(env));
let b_ev = Rc::new(b.evaluate(env));
match (*a_ev, *b_ev) {
(Expr::Integer(x), Expr::Integer(y)) => Expr::Integer(x + y),
_ => Expr::Plus(a_ev, b_ev),
}
}
Expr::Term(ref a) => *env.get(&a).unwrap(),
Expr::Set(ref a, ref b) => {
let b_ev = Rc::new(b.evaluate(env));
match **a {
Expr::Term(x) => {
let x_value = env.get_mut(&x).unwrap();
*x_value = *b_ev;
*b_ev
}
otherwise => {
let a_ev = Rc::new(a.evaluate(env));
Expr::Set(a_ev, b_ev)
}
}
}
otherwise => otherwise,
}
}
}
以上代码无法编译。每个match 似乎都借用了一个变量。此外,我认为我们不应该使用String 类型,但我不明白为什么。
编译错误:
error[E0277]: the trait bound `std::string::String: std::borrow::Borrow<&std::string::String>` is not satisfied --> src/main.rs:22:39 | 22 | Expr::Term(ref a) => *env.get(&a).unwrap(), | ^^^ the trait `std::borrow::Borrow<&std::string::String>` is not implemented for `std::string::String` | = help: the following implementations were found: <std::string::String as std::borrow::Borrow<str>>
【问题讨论】:
-
我建议发布诸如“此代码是否惯用?”之类的问题。到codereview.stackexchange.com
-
@Adrian 我同意,但代码审查需要工作代码,目前看来还不是。
-
对了,为什么要使用
Rc?通常表达式形成树,因此Expr的唯一所有者是包含它的外部Expr。我认为它不会解决您的任何编译错误,但不必要地使用Rc肯定不是惯用的。但是,String在字符串切片不合适或太痛苦时就可以了。 -
@delnan:“通常表达式形成树”。由于共享子表达式,通常是 DAG 的表达式。在这种情况下,一般情况下在编译时没有唯一所有者,因此您需要采用更通用的内存管理形式。在没有跟踪 GC 的情况下,引用计数是下一个最合乎逻辑的选择,尽管它速度较慢并且会泄漏周期。
标签: rust