【发布时间】:2020-11-30 15:38:26
【问题描述】:
我正在开发一个函数,它返回 Zip 存档中特定文件的内容。因为我知道文件的位置,所以我尝试使用ZipArchive.by_name 方法访问它。但是,文件名可能以不同的大小写书写。如果发生这种情况 (FileNotFound),我需要遍历存档中的所有文件并与模板执行不区分大小写的比较。但是,在这种情况下,我遇到了两个与借用有关的错误。
这是最小的示例(我使用 BarcodeScanner Android 应用程序 (../test_data/simple_apks/BarcodeScanner4.0.apk),但您可以使用任何 apk 文件,只需替换它的路径即可。您可以下载一个,例如在 ApkMirror 上):
use std::{error::Error, fs::File, path::Path};
const MANIFEST_MF_PATH: &str = "META-INF/MANIFEST.MF";
fn main() {
let apk_path = Path::new("../test_data/simple_apks/BarcodeScanner4.0.apk");
let _manifest_data = get_manifest_data(apk_path);
}
fn get_manifest_data(apk_path: &Path) -> Result<String, Box<dyn Error>> {
let f = File::open(apk_path)?;
let mut apk_as_archive = zip::ZipArchive::new(f)?;
let _manifest_entry = match apk_as_archive.by_name(MANIFEST_MF_PATH) {
Ok(manifest) => manifest,
Err(zip::result::ZipError::FileNotFound) => {
let manifest_entry = apk_as_archive
.file_names()
.find(|f| f.eq_ignore_ascii_case(MANIFEST_MF_PATH));
match manifest_entry {
Some(entry) => apk_as_archive.by_name(entry).unwrap(),
None => {
return Err(Box::new(zip::result::ZipError::FileNotFound));
}
}
}
Err(err) => {
return Err(Box::new(err));
}
};
Ok(String::new()) //stub
}
Cargo.toml:
[package]
name = "multiple_borrows"
version = "0.1.0"
authors = ["Yury"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
zip = "^0.5.8"
以下是错误:
error[E0502]: cannot borrow `apk_as_archive` as immutable because it is also borrowed as mutable
--> src/main.rs:17:34
|
14 | let _manifest_entry = match apk_as_archive.by_name(MANIFEST_MF_PATH) {
| ----------------------------------------
| |
| mutable borrow occurs here
| a temporary with access to the mutable borrow is created here ...
...
17 | let manifest_entry = apk_as_archive
| ^^^^^^^^^^^^^^ immutable borrow occurs here
...
31 | };
| - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `std::result::Result<ZipFile<'_>, ZipError>`
error[E0499]: cannot borrow `apk_as_archive` as mutable more than once at a time
--> src/main.rs:22:32
|
14 | let _manifest_entry = match apk_as_archive.by_name(MANIFEST_MF_PATH) {
| ----------------------------------------
| |
| first mutable borrow occurs here
| a temporary with access to the first borrow is created here ...
...
22 | Some(entry) => apk_as_archive.by_name(entry).unwrap(),
| ^^^^^^^^^^^^^^ second mutable borrow occurs here
...
31 | };
| - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `std::result::Result<ZipFile<'_>, ZipError>`
我了解这些错误与糟糕的架构决策有关。在这种情况下,最佳做法是什么?
【问题讨论】:
-
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?的答案可能会回答您的问题; Double mutable borrow error in a loop happens even with NLL on; Is it safe to logically split a borrow to work around a limitation of the NLL-enabled borrow-checker?。如果没有,请edit您的问题来解释差异。否则,我们可以将此问题标记为已回答。
-
我添加了最小的工作示例(它与前一个没有什么不同)。此外,我还添加了我的
Cargo.toml文件和 zip 依赖项。至于@Shepmaster 提供的链接,在我看来这不是 NLL 的问题,因为我使用的是最新的 Rust 版本。 -
这不是 NLL 的问题,因为我使用的是最新的 Rust 版本——这清楚地表明你没有完全阅读链接。链接中的所有问题都体现在当前 stable 编译器 Rust 1.48 中。
标签: rust borrow-checker borrowing