Продолжая изучать 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);
}