代码之家  ›  专栏  ›  技术社区  ›  Greg

如何在结构回调中使用外部对象,例如将数据追加到csv时?

  •  -1
  • Greg  · 技术社区  · 8 年前

    我的理解是,在作用域之外创建的对象在作用域内是可用的(因此允许进行阴影等操作),但在这种情况下似乎不起作用:

    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 回复  |  直到 8 年前
        1
  •  2
  •   Shepmaster Tim Diekmann    8 年前

    强烈地 鼓励你回去重新阅读 The Rust Programming Language 特别是关于 functions . 这段代码似乎显示了关于函数如何工作的整个模型的基本问题。

    例如,代码试图使用变量 wtr 在函数中 callback 而不是直接或间接地传递。

    如果这样的代码有效 ,程序员可能会讨厌使用这种语言,因为几乎不可能分辨出 什么 哪里 价值 WTR 甚至来自。

    解决方案很简单:将一段代码需要的任何值传递给该代码。然后很容易(或更容易)知道这个值是从哪里来的。有多种可行的方法。

    1. 将参数传递给 回拨 方法:

      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库方面还有其他问题,我忽略了这些问题,因为它们与您的问题无关。我鼓励您从一段简单的代码开始,让它工作起来,然后使它更复杂。这样,您一开始只处理简单的错误。

    一旦您了解了函数的基本用法,您可能希望了解 closures . 这些允许您从外部作用域“捕获”变量并将它们传入(与上面相同的两种方法中),而不必处理特定的变量计数或类型。

    在范围外创建的对象在范围内可用

    对于单个函数来说是这样的。它不适用于多个功能。

    因此允许阴影等情况

    阴影与范围无关。允许您在同一范围内进行阴影处理:

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

    . 这种语言存在;它们是 dynamic scope 有些人更喜欢它们。他们是少数民族,用这些语言编写的程序很难理解!