简体   繁体   English

Rust 相当于 Java 策略模式的消费者接口

[英]Rust equivalent of Java Consumer interface for Strategy pattern

I will provide a practical example.我将提供一个实际的例子。

I want to create an event logger.我想创建一个事件记录器。 I define an event as an Interface:我将事件定义为接口:

import java.util.function.Consumer;

interface Event {}

class BuyEvent implements Event {}

class SellEvent implements Event {}

A logger is simply a Consumer of events:记录器只是事件的消费者:

public static void main(String[] args) {
        Consumer<Event> logger;

        // Logger with method reference
        logger = System.out::println;
        logger.accept(new BuyEvent());

        // Logger with lambda
        logger = (event) -> {
            // Do something else
            System.out.println(event);
        };
        logger.accept(new BuyEvent());

I can also create a logger with state. For example:我还可以使用 state 创建一个记录器。例如:

class StatefulLogger implements Consumer<Event> {
    public StatefulLogger() {
    }

    @Override
    public void accept(Event event) {
        // Change state, then print event
        System.out.println(event);
    }
}

I can use the stateful logger as follows:我可以按如下方式使用有状态记录器:

public static void main(String[] args) {
        Consumer<Event> logger = new StatefulLogger("foo.txt");
        logger.accept(new BuyEvent());
}

I am trying to achieve the same in Rust.我正在尝试在 Rust 中实现相同的目标。

I define an event as an enum:我将事件定义为枚举:

#[derive(Debug)]
enum Event {
    BuyEvent,
    SellEvent,
}

I define a Logger trait and a struct with state that implements such trait:我定义了一个 Logger 特征和一个带有 state 的结构来实现这样的特征:

trait Logger {
    fn accept(&mut self, ev: Event);
}

struct StatefulLogger {}

impl Logger for StatefulLogger {
    fn accept(&mut self, ev: Event) {
        // Change state, then print event
        println!("{:?}", ev);
    }
}

I can use the logger as follows:我可以按如下方式使用记录器:

fn main() {
    let logger: &dyn Logger = &ComplexLogger {};
}

I would like to be able to assign a closure to the logger, much in the same spirit of Java.我希望能够为记录器分配一个闭包,与 Java 的精神大致相同。

fn main() {
    let consumer: fn(Event) = |ev: Event| {
        println!("{:?}", ev);
    };
}

To recap:回顾一下:

In Java, I had implemented a logger using a Strategy design pattern using the Consumer interface.在 Java 中,我使用 Consumer 接口使用 Strategy 设计模式实现了一个记录器。 A logger could both be a complex stateful object but also a lightweight lambda.记录器既可以是复杂的有状态的 object,也可以是轻量级的 lambda。

I would like to achieve the same in Rust, but I don't know how to proceed.我想在 Rust 中实现相同的目标,但我不知道如何进行。 I was not able to find similar examples on the Inte.net.我无法在 Inte.net 上找到类似的示例。 Also, does Rust provide an analogous to Java's Consumer interface?此外,Rust 是否提供类似于 Java 的 Consumer 接口?

There is no way to solve this fast in Rust, but you can create own macro to convert lambda to Logger impl and then return its object. Have a look at this repo .没有办法在 Rust 中快速解决这个问题,但您可以创建自己的宏将 lambda 转换为 Logger impl,然后返回其 object。看看这个repo If you want, I can write a solution soon.如果你愿意,我可以很快写一个解决方案。 In other way you can change your Logger trait to struct, where define field for consumer.以其他方式,您可以将Logger trait更改为结构,其中为消费者定义字段。 It gives you possibility to use as consumer any Fn(Event) ie if you have logger with state, you can move it to lambda and pass it or pass some fn directly.它使您可以将任何Fn(Event)作为消费者使用,即如果您有 state 的记录器,您可以将其移动到 lambda 并传递它或直接传递一些 fn。

#[derive(Debug)]
struct Event;

struct Logger<T>
where
    T: Fn(Event),
{
    consumer: T,
}

impl<T> Logger<T>
where
    T: Fn(Event),
{
    fn new(consumer: T) -> Self {
        Self { consumer }
    }

    fn accept(&self, event: Event) {
        (self.consumer)(event);
    }
}

struct StatefulLogger;

impl StatefulLogger {
    fn log(&self, event: Event) {
        println!("{:?}", event);
    }
}

fn log_fn(e: Event) {
    println!("{:?}", e);
}

fn main() {
    let foo = |e: Event| println!("{:?}", e);
    let logger_lambda = Logger::new(foo);

    let stateful_logger = StatefulLogger;
    let logger_struct = Logger::new(move |e| stateful_logger.log(e));

    let logger_fn = Logger::new(log_fn);

    logger_lambda.accept(Event);
    logger_struct.accept(Event);
    logger_fn.accept(Event);
}

About consumer interface, have a look on Fn, FnMut and FnOnce traits.关于用户界面,请查看 Fn、FnMut 和 FnOnce 特性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM