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

Учитывая структуру «делегат», которая имеет член «обработчик», как я могу вызвать обработчик с динамической строкой?

pub struct Processor {
    callback: Box<FnMut()>,
    message: Option<String>
}

impl Processor {
    pub fn new<CB: 'static + FnMut()>(c: CB) -> Self {
        Processor {
            callback: Box::new(c),
            message: Some("".into())
        }
    }

    pub fn set_callback<CB: 'static + FnMut(&str)>(&mut self, callback: CB) {
        self.callback = Box::new(callback);
    }

    pub fn set_message<S>(&mut self, message: S) where S: Into<String> {
        self.message = Some(message.into());
    }

    pub fn process(&mut self) {
        match self.message {
            Some(string) => {
                if self.message.chars().count() > 0 {
                    (self.callback)(self.message);
                } else {
                    (self.callback)();
                }
            },
            None => {}
        }
    }
}

impl EventEmitter {
    pub fn new() -> Self {
        EventEmitter {
            delegates: Vec::new()
        }
    }

    /// Register an Event and a handler
    pub fn on(&mut self, event: Event, handler: Processor) {
        self.delegates.push(Delegate::new(event, handler))
    }

    /// Run handlers on the emitted event
    pub fn emit(&mut self, name: &'static str/*, with message!! */) {
        for delegate in self.delegates.iter_mut(){
            if delegate.event.name == name {
                delegate.handler.process();
            }
        }
    }

    /// Run handlers on the emitted event
    pub fn emit_with(&mut self, name: &'static str, message: &'static str) {
        for delegate in self.delegates.iter_mut() {
            if delegate.event.name == name {
                delegate.handler.set_message(message);
                delegate.handler.process();
            }
        }
    }
}

Затем у меня будет:

emitter.on(
    Event::new("TEST"), 
    Processor::new(|x| println!("Test: {}", x))
);
emitter.emit_with("TEST", "test");

Но компилятор жалуется:

  --> src/main.rs:97:3
   |
97 |         Processor::new(|x| println!("Test: {}", x))
   |         ^^^^^^^^^^^^^^ --- takes 1 argument
   |         |
   |         expected closure that takes 0 arguments

Если я удалю аргумент типа "& str" в определении set_callback ():

set_callback<CB: 'static + FnMut()>(&mut self, callback: CB)

Я могу заставить это работать, используя замыканиеэто не принимает никаких аргументов:

emitter.on( // emitter.emit("TEST");
    Event::new("TEST"), 
    Processor::new(|| println!("static string."))
);

Есть ли способ передать строку в функцию emit_with (), которую в конечном итоге можно передать обработчику?

1 Ответ

0 голосов
/ 07 февраля 2019

Здесь вы написали:

pub struct Processor {
    callback: Box<FnMut(/* RIGHT HERE */)>,
    message: Option<String>
}

Вы объявили FnMut (замыкание), которое не принимает аргументов.Синтаксис FnMut(/* arguments to closure */), но вы его не указали.Таким образом, вы не можете передать это закрытие, что принимает аргументы. Вы не можете иметь замыкание, которое одновременно принимает аргумент и не принимает аргумент одновременно.

Кроме того, вы использовали FnMut(&str), но только в одном месте.Вам это нужно во всех местах.Поскольку вы хотите передать или не передать строку, я преобразовал ее в Optional<&str> (чтобы тип замыкания был FnMut(Option<&str>)).

Я изменил ваш код так, что замыкание принимаетнеобязательно &str.Вот как я бы посоветовал вам разобраться с этим:

pub struct Processor {
    // The closure takes an optional string.
    callback: Box<FnMut(Option<&str>)>,
    message: Option<String>
}

impl Processor {
    pub fn new<CB: 'static + FnMut(Option<&str>)>(c: CB) -> Self {
        Processor {
            callback: Box::new(c),
            message: Some("".into())
        }
    }

    pub fn set_callback<CB: 'static + FnMut(Option<&str>)>(&mut self, callback: CB) {
        self.callback = Box::new(callback);
    }

    pub fn set_message<S>(&mut self, message: S) where S: Into<String> {
        self.message = Some(message.into());
    }

    pub fn process(&mut self) {
        match self.message {
            Some(string) => {
                // NOTE: Instead of .chars().count > 0
                if !self.message.is_empty() {
                    (self.callback)(Some(self.message));
                } else {
                    (self.callback)(None);
                }
            },
            None => {}
        }
    }
}

ПРИМЕЧАНИЕ : Это не проверено, но, вероятно, должно работать.Если появятся какие-либо ошибки, оставьте комментарий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...