我在这里遇到 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
Run Code Online (Sandbox Code Playgroud)
我正在编写的这个程序使用 Rust 的 MPI 库,但现在让我们忽略它,因为它不是我的问题的一部分。
问题是,我File在函数顶部声明了一个可变对象main(),但在开始时未初始化。现在因为我使用的是 MPI,所以这是一个多进程程序。我正在对此进行一些简化,并删除对我的问题来说不必要的代码。
my_rank变量基本上保存当前正在执行的进程的“进程ID”,因为相同的代码可以由多个进程运行。进程my_rank == 0只负责将输出打印到文件,其他进程都不执行此操作。在 的进程中my_rank == 0,output_file_handler是“活动的”,而在其他进程中,它保持未初始化状态,只是从未使用过。
除了声明之外,所有对 的访问都output_file_handler在进程中my_rank == 0,因此它在使用时总是被初始化。然而,编译器太愚蠢而无法意识到这一点,而且太严格,因此它会惩罚完美的代码!
首先我有 的声明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将会超出范围并在 处被销毁},我想稍后使用它将来。这就是为什么我必须将 the 放在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?");
}
}
Run Code Online (Sandbox Code Playgroud)
在您的程序中,有一个条件子句,其中 on 腿设置output_file_handler,而 one 不设置。让我们从一个简化的例子开始:
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?");
}
Run Code Online (Sandbox Code Playgroud)
使用一个简单的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?");
}
Run Code Online (Sandbox Code Playgroud)
如果您可以确保 else 块以防止以后使用 的方式设置所有变量,output_file_handler则可能会有更复杂的解决方案,而无需Option.