我试着用Rust和Excel做一些简单的事情。有时候我想创建一个HashMap,键=工作表,值=行。我用office crate来处理Excel。
现在我创建了下面的代码:
let mut workSheets: HashMap<String, Rows> = HashMap::new();
let mut range: Range;
for conf in config.supa{
range = excel.worksheet_range(&conf.worksheet).unwrap_or_else(|err|{
panic!("The Config-File contains worksheets, which are not present in your Excel-File. Notice that names must match exactly. Error: {}", err);
});
let _option = workSheets.insert(conf.worksheet, range.rows());
}
这段代码在for循环中的“range”变量上给出了以下错误:
error[E0506]: cannot assign to `range` because it is borrowed
--> src/main.rs:45:9
|
45 | range = excel.worksheet_range(&conf.worksheet).unwrap_or_else(|err|{
| ^^^^^ assignment to borrowed `range` occurs here
...
49 | let _option = workSheets.insert(conf.worksheet, range.rows());
| -----------------------------------------------
| | |
| | borrow of `range` occurs here
| borrow later used here
For more information about this error, try `rustc --explain E0506`.
error: could not compile `supa_importer` due to previous error
即使一遍又一遍地阅读this,我还是不明白。我怎么能用一种生 rust 的方式来解决这个问题呢?
2条答案
按热度按时间8yparm6h1#
当你调用
range.rows()
的时候,它会引用range
。请看这里的&self
参数。把Rows
存储在你的HashMap
中是不可行的。因为它不拥有基础数据(您的range
变量拥有您想要通过Rows
迭代器访问的数据)。一个更好的解决方案是在HashMap
中存储Range
而不是Rows
(这样HashMap
的条目将拥有数据),并在需要时对某个值调用.rows()
。然后,您可以像这样访问
Rows
,例如:km0tfn4u2#
首先,用
calamine
代替office
。原因在注解中解释。让我们先把它弄清楚。实际错误时打开:Jonas已经提供了一个解决方案,所以我将进一步解释“为什么”以及需要注意什么。
关键是始终密切关注一个类型是否拥有其所有数据的所有权(在Rust术语中,“被拥有的类型”),或者它是否拥有对其他数据的引用。判断一个类型是否是“被拥有的类型”的一个简单方法是检查其生存期的类型签名(以一个勾号开头的类型参数,通常为
'a
)。拥有类型是最容易使用的,因为它们包含(也称为拥有)自己的数据副本,并且不与任何其他内容关联(也称为包含对任何其他内容的引用)。
然而,通常你不想总是复制内存(克隆)底层数据,就像大多数迭代器的情况一样,因为你在其他地方持有对某个数据片段的引用,所以当你拥有引用时,该数据片段一定不能被释放。
如果你看一下
Rows
struct的签名(通过Range::rows
函数获得),您可以在其类型参数中看到前面提到的'a
,这是有意义的,因为它是Range
结构体所拥有的数据上的迭代器。如果要存储此结构体,则需要保存对它所引用的Range
结构体的持久引用,这正是你犯的错误。在循环的每次迭代中,都要将
Range
存储在range
变量中,并存储对此Range
的底层数据的引用(以Rows
结构体的形式)。但是在下一次迭代中,range
变量被重新赋值,这意味着它的旧底层数据被释放,使所有指向它的引用无效。悬空引用是非内存安全语言中一个非常常见的错误,并且在安全Rust中是不允许的,因此您的错误“cannot assign torange
because it is borrown”。如果您感兴趣,可以尝试在循环中移动
let range = ...
,观察错误如何变化,这样可能会更有意义。