随着我继续学习Rust,我正在从事一个涉及谓词功能广泛使用的项目。我决定使用Rust闭包来实现这些谓词,例如:
type Predicate = Box<Fn(&Form) -> bool>
。
我的程序使用应用于这些谓词的布尔逻辑。例如,and
和or
都应用于这些谓词的值。我使用Box::leak
:
struct Form {
name: String,
}
fn and(a: Option<Predicate>, b: Option<Predicate>) -> Option<Predicate> {
if a.is_none() {
return b;
} else if b.is_none() {
return a;
} else {
let a = Box::leak(a.unwrap());
let b = Box::leak(b.unwrap());
return Some(Box::new(move |form: &Form| a(form) && b(form)));
}
}
虽然这似乎可以按照我的意愿进行,但Box::leak
似乎并不理想。我对std::rc::Rc
和std::cell::RefCell
不太了解,是否可以帮助我避免在这里使用Box::leak
-使用它们可能需要对我的代码进行重大的重组,但我想最不了解这里的惯用方法。
有没有办法避免泄漏,同时仍保持相同的功能?
struct Form {
name: String,
}
type Predicate = Box<Fn(&Form) -> bool>;
struct Foo {
predicates: Vec<Predicate>,
}
impl Foo {
fn and(a: Option<Predicate>, b: Option<Predicate>) -> Option<Predicate> {
if a.is_none() {
return b;
} else if b.is_none() {
return a;
} else {
let a = Box::leak(a.unwrap());
let b = Box::leak(b.unwrap());
return Some(Box::new(move |form: &Form| a(form) && b(form)));
}
}
}
fn main() {
let pred = Foo::and(
Some(Box::new(move |form: &Form| {
form.name == String::from("bar")
})),
Some(Box::new(move |_: &Form| true)),
)
.unwrap();
let foo = Foo {
predicates: vec![pred],
};
let pred = &foo.predicates[0];
let form_a = &Form {
name: String::from("bar"),
};
let form_b = &Form {
name: String::from("baz"),
};
assert_eq!(pred(form_a), true);
assert_eq!(pred(form_b), false);
}
答案 0 :(得分:4)
您的代码不需要Box::leak
,目前尚不清楚您为什么这么认为。如果继续删除,代码将继续编译并具有相同的输出:
impl Foo {
fn and(a: Option<Predicate>, b: Option<Predicate>) -> Option<Predicate> {
if a.is_none() {
b
} else if b.is_none() {
a
} else {
let a = a.unwrap();
let b = b.unwrap();
Some(Box::new(move |form: &Form| a(form) && b(form)))
}
}
}
unwrap
是非惯用语;更加惯用的解决方案将使用match
:
impl Foo {
fn and(a: Option<Predicate>, b: Option<Predicate>) -> Option<Predicate> {
match (a, b) {
(a, None) => a,
(None, b) => b,
(Some(a), Some(b)) => Some(Box::new(move |form| a(form) && b(form))),
}
}
}