我有一个文件main.rs
和一个文件rule.rs
。我想在rule.rs
中定义要包含在Rules::rule
向量中的函数,而不必一一推送。我希望有一个循环来推动它们。
main.rs :
struct Rules {
rule: Vec<fn(arg: &Arg) -> bool>,
}
impl Rules {
fn validate_incomplete(self, arg: &Arg) -> bool {
// iterate through all constraints and evaluate, if false return and stop
for constraint in self.incomplete_rule_constraints.iter() {
if !constraint(&arg) {
return false;
}
}
true
}
}
rule.rs :
pub fn test_constraint1(arg: &Arg) -> bool {
arg.last_element().total() < 29500
}
pub fn test_constraint2(arg: &Arg) -> bool {
arg.last_element().total() < 35000
}
Rules::rule
应填充test_constraint1
和test_constraint2
。
在Python中,我可以在要包含在@rule_decorator
中的约束之上添加装饰器Vec
,但在Rust中看不到装饰器。
在Python中,我可以使用dir(module)
查看所有可用的方法/属性。
Python变体:
class Rules:
def __init__(self, name: str):
self.name = name
self.rule = []
for member in dir(self):
method = getattr(self, member)
if "rule_decorator" in dir(method):
self.rule.append(method)
def validate_incomplete(self, arg: Arg):
for constraint in self.incomplete_rule_constraints:
if not constraint(arg):
return False
return True
使用rule.py文件:
@rule_decorator
def test_constraint1(arg: Arg):
return arg.last_element().total() < 29500
@rule_decorator
def test_constraint1(arg: Arg):
return arg.last_element().total() < 35000
所有带有rule_decorator
的函数都将添加到self.rule
列表中,并由validate_incomplete
函数选中。
答案 0 :(得分:0)
Rust没有与Python相同的反射功能。特别是,您不能在运行时遍历模块的所有功能。至少您不能使用内置工具来做到这一点。可以编写所谓的过程宏,使您可以向函数中添加自定义属性,例如#[rule_decorator] fn foo() { ... }
。使用proc宏,您几乎可以执行任何操作。
但是,为此,使用proc宏的方法过于工程化(我认为)。就您而言,我只列出所有要包含在向量中的函数:
fn test_constraint1(arg: u32) -> bool {
arg < 29_500
}
fn test_constraint2(arg: u32) -> bool {
arg < 35_000
}
fn main() {
let rules = vec![test_constraint1 as fn(_) -> _, test_constraint2];
// Or, if you already have a vector and need to add to it:
let mut rules = Vec::new();
rules.extend_from_slice(
&[test_constraint1 as fn(_) -> _, test_constraint2]
);
}
有关此代码的一些注意事项:
&Arg
替换为u32
,因为它与问题无关。请忽略有关StackOverflow问题的不必要的详细信息。_
以提高可读性。as fn(_) -> _
强制转换是很必要的。您可以在this question中阅读有关它的更多信息。答案 1 :(得分:0)
您可以通过一些调整和限制来实现您的目标。您需要使用inventory crate。目前仅限于Linux,macOS和Windows 。
然后,您可以使用inventory::submit
将值添加到全局注册表,inventory::collect
来构建注册表,并使用inventory::iter
来遍历注册表。
由于语言限制,您无法为不属于您的类型的值(包括原始函数指针)创建注册表。我们将需要创建一个名为Predicate
的 newtype 来使用板条箱:
use inventory; // 0.1.3
struct Predicate(fn(&u32) -> bool);
inventory::collect!(Predicate);
struct Rules;
impl Rules {
fn validate_incomplete(&self, arg: &u32) -> bool {
inventory::iter::<Predicate>
.into_iter()
.all(|Predicate(constraint)| constraint(arg))
}
}
mod rules {
use super::Predicate;
pub fn test_constraint1(arg: &u32) -> bool {
*arg < 29500
}
inventory::submit!(Predicate(test_constraint1));
pub fn test_constraint2(arg: &u32) -> bool {
*arg < 35000
}
inventory::submit!(Predicate(test_constraint2));
}
fn main() {
if Rules.validate_incomplete(&42) {
println!("valid");
} else {
println!("invalid");
}
}
要实现最初设定的目标,您还需要采取一些其他步骤:
“向量”
您可以从提供的迭代器中collect
来构建Vec
。
“装饰函数”
您可以编写自己的程序宏,该宏将为您调用inventory::submit!(Predicate(my_function_name));
。
“来自特定模块”
您可以将the module name添加到Predicate
结构中并稍后对其进行过滤。
另请参阅: