Как использовать внешний объект в обратном вызове структуры, например, при добавлении данных в CSV? - PullRequest
0 голосов
/ 22 мая 2018

Насколько я понимаю, объекты, созданные вне области действия, доступны внутри области действия (следовательно, разрешены такие вещи, как теневое копирование), но в этом сценарии это не работает:

extern crate csv;
extern crate rand;

use rand::Rng;
use std::path::Path;
use std::time::SystemTime;

#[derive(Debug)]
struct Event {
    time: SystemTime,
    value: u32,
}

impl Event {
    fn new(t: SystemTime, n: u32) -> Event {
        Event {
            time: SystemTime,
            value: n,
        }
    }
}

struct Process;

impl Process {
    fn new() -> Process {
        Process {}
    }

    fn start(&self) {
        loop {
            let now = SystemTime::now();
            let random_number: u32 = rand::thread_rng().gen();
            let event = Event::new(now, random_number);
            self.callback(event);
        }
    }

    fn callback(&self, event: Event) {
        println!("{:?}", event);
        wtr.write_record(&event).unwrap();
        wtr.flush().unwrap();
    }
}

fn main() {
    let file_path = Path::new("test.csv");
    let mut wtr = csv::Writer::from_path(file_path).unwrap();

    let process: Process = Process::new();
    process.start();
}

Ошибки:

error[E0423]: expected value, found struct `SystemTime`
  --> src/main.rs:17:19
   |
17 |             time: SystemTime,
   |                   ^^^^^^^^^^ constructor is not visible here due to private fields

error[E0425]: cannot find value `wtr` in this scope
  --> src/main.rs:41:9
   |
41 |         wtr.write_record(&event).unwrap();
   |         ^^^ not found in this scope

error[E0425]: cannot find value `wtr` in this scope
  --> src/main.rs:42:9
   |
42 |         wtr.flush().unwrap();
   |         ^^^ not found in this scope

Как добавить данные (Event) в файл CSV из функции обратного вызова для Process?

1 Ответ

0 голосов
/ 22 мая 2018

I настоятельно рекомендую вам вернуться и перечитать Язык программирования Rust , в частности главу о функциях .Этот код, по-видимому, показывает фундаментальные проблемы вокруг всей модели работы функций.

Например, код пытается использовать переменную wtr в функции callback без ее прямой передачи.или косвенно.

Если бы такой код работал 1 , программисты, скорее всего, не хотели бы иметь дело с этим языком, потому что было бы почти невозможно сказать что и где значение wtr даже взято.

Решение простое: передайте любое значение, необходимое фрагменту кода, этому коду.Тогда легко (или проще) определить, откуда взято значение.Есть несколько путей, которые могут работать.

  1. Передать аргумент методу callback:

    use std::io::Write;
    
    impl Process {
        fn start<R>(&self, wtr: &mut csv::Writer<R>)
        where
            R: Write,
        {
            loop {
                // ...
                self.callback(wtr, event);
            }
        }
    
        fn callback<R>(&self, wtr: &mut csv::Writer<R>, event: Event)
        where
            R: Write,
        {
            // ...
        }
    }
    
    fn main() {
        // ...
        process.start(&mut wtr);
    }
    
  2. Передать аргумент вконструктор и сохраните его внутри структуры:

    use std::io::Write;
    
    struct Process<'a, R>
    where
        R: Write + 'a,
    {
        wtr: &'a mut csv::Writer<R>,
    }
    
    impl<'a, R> Process<'a, R>
    where
        R: Write,
    {
        fn new(wtr: &'a mut csv::Writer<R>) -> Self {
            Process { wtr }
        }
    
        // ...
    
        fn callback(&self, event: Event) {
            // ...
            self.wtr.write_record(event).unwrap();
            self.wtr.flush().unwrap();
        }
    }
    
    fn main() {
        // ...
        let process = Process::new(&mut wtr);
    }
    

У кода есть другие проблемы с использованием библиотеки CSV, которые я игнорирую, поскольку они не связаны с вашим вопросом.Я призываю вас начать с более простого куска кода, заставить его работать, а затем сделать его более сложным.Таким образом, вначале вы имеете дело только с более простыми ошибками.

Как только вы поймете это основное использование функций, вы можете узнать о замыканиях .Они позволяют вам «захватывать» переменные из внешней области видимости и передавать их (в тех же двух методах, что и выше) без необходимости иметь дело с определенным количеством или типом переменных.

объекты, созданные внеобласти видимости доступны внутри области видимости

Это верно для одной функции.Это не относится ко всем функциям.

Следовательно, такие вещи, как теневое копирование, разрешены

Затенение не имеет ничего общего с областями видимости.Вам разрешено скрывать в одной области:

let a = Some(32);
let a = a.unwrap();

1 .Такие языки существуют;это языки с динамической областью действия , и некоторые люди предпочитают их.Они в меньшинстве, программы, написанные на этих языках, трудно рассуждать!

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