Как создать вектор всех декорированных функций из определенного модуля? - PullRequest
1 голос
/ 13 апреля 2019

У меня есть файл 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.

1 Ответ

0 голосов
/ 13 апреля 2019

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(_) -> _ актерский состав крайне необходим. Вы можете прочитать больше об этом в этом вопросе .
...