可能未初始化的变量的借用–对我来说,对于程序员来说,它将始终被初始化是显而易见的

问题描述 投票:0回答:1

我在这里遇到Rust编译器问题。该代码最初是用C编写的,我的工作是将其移植到Rust代码中。我没有在这里修改算法或任何东西,但是Rust编译器比C编译器严格,并且标记了完全有效的代码。

error[E0381]: borrow of possibly-uninitialized variable: `output_file_handler`
   --> src/main.rs:318:9
    |
318 |         output_file_handler.write(b"Why won't it work?");
    |         ^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `output_file_handler`

error: aborting due to previous error

我正在编写的该程序使用用于Rust的MPI库,但是现在就忽略它,因为它不是我的问题的一部分。

问题是,我在File函数的顶部声明了一个可变的main()对象,但该对象在开始时未初始化。现在,因为我正在使用MPI,所以这是一个多进程程序。我正在对此进行一些简化,并删除了不必要的代码来解决我的问题。

my_rank变量基本上保留当前正在执行的进程的“进程ID”,因为同一代码可以由多个进程运行。使用my_rank == 0的过程仅负责将输出打印到文件,没有其他过程执行此操作。在使用my_rank == 0的过程中,output_file_handler是“活动的”,而在其他过程中,它保持未初始化状态,因此根本不使用它。

除声明外,output_file_handler的所有和任何访问都在使用my_rank == 0进行处理,因此在使用时始终会对其进行初始化。但是,编译器过于笨拙,无法意识到这一点,而且过于严格,因此会对Perfectly good code

造成不利影响。

首先,我得到了output_file_handler的声明。然后,我有一些代码启动MPI子系统并“分叉”一堆进程,并为每个进程分配其各自的等级。然后,在my_rank == 0中初始化output_file_handler。然后,稍后将执行所有计算密集型任务,包括消息传递,这些任务将为所有进程共享。然后,完成后,output_file_handler应该将这些计算的结果写入文件中。

我无法将这些计算下方的output_file_handler的初始化移到直接写入输出的位置,因为如果无法打开该输出文件,则根本不应启动这些密集的计算。

output_file_handler必须在整个main()函数中具有范围,从函数顶部开始,因为如果我在if my_rank == 0块之一中对其进行定义,则output_file_handler将超出范围并在}处销毁,我希望以后再使用它。这就是为什么我必须将output_file_handler放在全局范围内的原因,因为我没有其他方法可以从初始化中获取File对象,因为每个if { }语句都是自包含的,并且是获取该方法的唯一方法他们要做的就是在下一个较低级别使用更大的范围。而且我认为,当File对象超出范围时,实际文件将关闭。我不希望这种情况发生。

请原谅我对Rust的了解不足,但是到目前为止,我对那种编程语言的了解还很少,我的工作是将该应用程序从C移植到Rust。不,除了MPI,我不能将其他任何库用于多线程/多处理。

fn main() {
    // Because the mpirun executable itself generates standard error and standard output,
    // I need to create a new File where the application's output should be written.
    let mut output_file_handler : File;
    // Similarly, this is the File where the application's timing information shoudl be written.
    let mut timing_file_handler : File;

    let universe = mpi::initialize().unwrap();
    let world = universe.world();

    let comm_size : i32 = world.size();
    let my_rank   : i32 = world.rank();

    /* Some more code here... */

    // Open up the output file.
        let output_filename : String = "output".to_string();

        // The create() static method opens a file in write-only mode.
        // If the file already existed, the old content is destroyed. Otherwise, a new file is created.
        let create_file_handler = File::create(&output_filename);
        // If File::create() succeeds, it returns an instance of Ok() that contains a file handler.
        // If File::create() fails, it returns an instance of Err() that contains more information about the kind of error that happened.
        output_file_handler = match create_file_handler {
            Ok(file) => {
                let dummy : i8 = 5;
                // Send the success message to all processes.
                for i in 0..comm_size {
                    world.process_at_rank(i).send_with_tag::<i8>(&dummy, 100);
                }

                file  // quantity without a ; at the end, is returned by the match statement
            },

            Err(error) => {
                eprintln!("ERROR: Could not open the file {} for writing output.", output_filename);
                process::abort();
            }
        };
    // Make the other ranks either wait for a success message to be sent, or be killed upon failure.
    // This is used as a synchronization device.
    } else {
        // recieve_with_tag::<i8>() returns a tuple `(i8, mpi::point_to_point::Status)`
        // recieve_with_tag::<i8>() takes the tag as a parameter.
        let __dummy = (world.process_at_rank(0).receive_with_tag::<i8>(100)).0;
    }


    /* After that is done, there is a lot of very intensive computations performed here.
       This code is shared by all the processes. */

    // Later, the final output is written to the file.
    if my_rank == 0 {
        output_file_handler.write(b"Why won't it work?");
    }

}
rust compilation
1个回答
0
投票

在您的程序中有一个条件子句,其中腿设置output_file_handler,而没有。让我们从一个简化的示例开始:

fn main() {
  let mut output_file_handler: File;

  if true {
    let output_filename: String = "output".to_string();

    let create_file_handler = File::create(&output_filename);
    output_file_handler = match create_file_handler {
      Ok(file) => file,

      Err(error) => {
        println!(
          "ERROR: Could not open the file {} for writing output.",
          output_filename
        );
        process::abort();
      }
    };
  } else {
    // output_file_handler is not set
  }

  output_file_handler.write(b"Why won't it work?");
}

使用简单的Option<File>将使它看起来像:

fn main() {
  let mut output_file_handler: Option<File>;

  if true {
    let output_filename: String = "output".to_string();

    let create_file_handler = File::create(&output_filename);
    output_file_handler = match create_file_handler {
      Ok(file) => Some(file),

      Err(error) => {
        println!(
          "ERROR: Could not open the file {} for writing output.",
          output_filename
        );
        process::abort();
      }
    };
  } else {
    output_file_handler = None;
  }

  output_file_handler.unwrap().write(b"Why won't it work?");
}

[如果可以确保else块以防止以后使用output_file_handler的方式设置所有变量,那么即使没有Option,可能会有更复杂的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.