Как использовать wirefilter над бесконечным потоком данных - PullRequest
1 голос
/ 29 апреля 2019

Я пишу программу для использования wirefilter для фильтрации данных из бесконечного потока.

Но кажется, что я не могу использовать скомпилированный ast в цикле из-за времени жизни, и когда я пытаюсь скомпилировать, это вывод:

error: borrowed data cannot be stored outside of its closure
  --> src/main.rs:34:33
   |
31 |     let filter = ast.compile();
   |         ------ ...so that variable is valid at time of its declaration
32 | 
33 |     for my_struct in data.filter(|my_struct| {
   |                                  ----------- borrowed data cannot outlive this closure
34 |         let execution_context = my_struct.execution_context();
   |                                 ^^^^^^^^^ ----------------- cannot infer an appropriate lifetime...
   |                                 |
   |                                 cannot be stored outside of its closure

error: aborting due to previous error

error: Could not compile `wirefilter_playground`.

To learn more, run the command again with --verbose.

main.rs

use wirefilter::{ExecutionContext, Scheme};

lazy_static::lazy_static! {
    static ref SCHEME: Scheme = Scheme! {
        port: Int
    };
}

#[derive(Debug)]
struct MyStruct {
    port: i32,
}

impl MyStruct {
    fn scheme() -> &'static Scheme {
        &SCHEME
    }

    fn execution_context(&self) -> ExecutionContext {
        let mut ctx = ExecutionContext::new(Self::scheme());
        ctx.set_field_value("port", self.port).unwrap();

        ctx
    }
}

fn main() -> Result<(), failure::Error> {
    let data = expensive_data_iterator();
    let scheme = MyStruct::scheme();
    let ast = scheme.parse("port in {2 5}")?;
    let filter = ast.compile();

    for my_struct in data.filter(|my_struct| {
        let execution_context = my_struct.execution_context();
        filter.execute(&execution_context).unwrap()
    }).take(10) {
        println!("{:?}", my_struct);
    }

    Ok(())
}

fn expensive_data_iterator() -> impl Iterator<Item=MyStruct> {
    (0..).map(|port| MyStruct { port })
}

Cargo.toml

[package]
name = "wirefilter_playground"
version = "0.1.0"
edition = "2018"

[dependencies]
wirefilter-engine = "0.6.1"
failure = "0.1.5"
lazy_static = "1.3.0"

возможно ли заставить его работать? Я хотел бы предоставить только отфильтрованные данные для конечного пользователя, в противном случае объем данных будет огромным в памяти. Заранее спасибо!

1 Ответ

2 голосов
/ 29 апреля 2019

Похоже, проблема в пожизненном отбрасывании взамен структур.В частности, этот код:

fn execution_context(&self) -> ExecutionContext {
    //...
}

эквивалентен этому:

fn execution_context<'s>(&'s self) -> ExecutionContext<'s> {
    //...
}

, который становится очевидным, как только вы поймете, что ExecutionContext имеет ассоциированное время жизни.

Время жизни ExecutionContext не обязательно должно совпадать с временем жизни MyStruct, поэтому вы, вероятно, захотите написать:

fn execution_context<'e>(&self) -> ExecutionContext<'e> {
    //...
}

или, возможно:

fn execution_context<'s, 'e>(&'s self) -> ExecutionContext<'e>
where 'e: 's {
    //...
}

в зависимости от того, будет ли ваш контекст в конечном итоге ссылаться на какой-либо контент MyStruct.

...