我想获取一个链表并用结构实例填充它,但前提是该列表还没有包含我正在考虑添加的项目。
我正在使用积分,所以如果(3,5)在列表中我不想添加它,否则我会这样做。
我目前的代码:
use std::collections::LinkedList;
struct Location {
x: i32,
y: i32,
}
fn main() {
let mut locations = LinkedList::new();
loop {
let location_set = &mut locations;
// Scanner stuff happens.
if !has_location(location_set, &next_checkpoint_x, &next_checkpoint_y) {
let point = Location {
x: next_checkpoint_x,
y: next_checkpoint_y,
};
locations.push_back(point);
}
}
}
fn has_location(location_list: LinkedList<Location>, target_x: &i32, target_y: &i32) -> bool {
true // Just until I can figure out this mutability stuff
}
我已经能够通过这些变化来运行它,但这对我来说似乎不对。
loop {
if !has_location(&mut locations, &next_checkpoint_x, &next_checkpoint_y) {
// stuff
}
}
fn has_location(location_list: &LinkedList<Location>, target_x: &i32, target_y: &i32) -> bool {
true
}
我不希望has_location
能够改变链接列表,我只是希望它能够借用它以便它可以查看它的内部。我不想考虑影响它检查的链表的has_location
(或类似功能)。这就是我创建location_set
的原因。我想要一些东西以只读的方式引用位置,并且要传递给has_location
函数,以及在调用has_location
函数后被引用的(位置)不被破坏的位置。我在函数调用中传递了&
参数,因为我不希望传递的参数被破坏 - 所以我想借用它们?
我想要的东西是否有意义 - 如果我最初将位置声明为可变链表,我可以将其不可变版本传递给要评估的函数吗?
答案 0 :(得分:2)
如果您有可变借款,您可以随时重新借用它作为不可变借款。这甚至会隐式发生(&mut T
将强制转换为&T
)。因此,您可以直接将location_set
传递给has_location
。或者,如果您想明确该函数不会改变其参数,您可以编写&*location_set
而不是location_set
(尽管我认为这是不必要的)。
另外,请注意,在存在不可变借入的情况下,您不能使用可变借入;不可变借用在数据结构范围内冻结数据结构。同样,你不能使用变量,而在范围内对该变量进行可变借用。在您的第一个代码示例中,当locations
在范围内时,您无法引用location_set
,因为location_set
在locations
上进行了可变借用,但您可以再次使用location_set
,因为push_back
只需要一个可变的借位(它不会按值LinkedList
)。
仅检查数据结构的函数通常会接收到数据结构的不可变借位。如果数据结构是通过值传递的,那么函数将取得它的所有权,因此在返回之前将其销毁(除非它被移动到别处)。因此,是的,您希望has_location
接受LinkedList
的不可变借入。通过接受不可变借用(而不是可变借用),编译器将阻止您修改LinkedList
(除非您使用不安全的代码)。
全部放在一起:
use std::collections::LinkedList;
struct Location {
x: i32,
y: i32,
}
fn main() {
let mut locations = LinkedList::new();
let next_checkpoint_x = 0;
let next_checkpoint_y = 0;
loop {
let location_set = &mut locations;
// Scanner stuff happens.
if !has_location(location_set, &next_checkpoint_x, &next_checkpoint_y) {
let point = Location { x: next_checkpoint_x, y: next_checkpoint_y };
location_set.push_back(point);
}
}
}
fn has_location(location_list: &LinkedList<Location>, target_x: &i32, target_y: &i32) -> bool {
true
}
我不明白的是,在你的例子中,
location_set
直接传递给has_location
(所以函数拥有它,对吧?)。这在我看来意味着在has_location
范围的末尾,location_set
应该被销毁,不是吗?如何在location_set
块中继续使用if
?
不,has_location
不拥有location_set
。如果这是任何其他未实现Copy
的类型(例如String
),那么您就是对的,但引用有特殊规则可以使它们更方便使用。
当您传递对函数的引用时,编译器将自动重新启动该引用以生成新引用,通常具有更短的生命周期。在这里,编译器重新借用可变引用并生成不可变引用;在不可变引用超出范围之前,不能使用可变引用(不可变引用未绑定到此处的变量,因此您不会注意到这一点)。从概念上讲,它就好像你传递了一个不可变引用的可变引用(在Rust中,& &mut T
不允许你改变T
,因为可能有多个副本那个外部参考文献),它只是两个参考文献被压平了#34;。
此外,如果
location_set
是不可变的,push_back
如何能够添加到列表的末尾,是因为该函数将可变借入强制转换为不可变借用?
location_set
仍然是一个可变引用(因为我们使用&mut
运算符创建它)。 has_location
对不可变引用进行操作的事实并未改变location_set
是可变引用的事实。一旦评估了对has_location
的调用,location_set
可以作为可变引用重用,因此允许push_back
等变异操作。
请记住,可变性是Rust纯粹是一个编译时的概念; mut
或缺少mut
只是让编译器验证您的代码不会进行非法操作,但是一旦编译完代码,这些标记就无处可见。