fre*_*inn 0 reference mutable immutability rust
我想要一个调用其他相互递归函数的函数,但我已经有了这样的类型签名:
fn f1(mut index: &mut usize, ..)
fn f2(mut index: &mut usize, ..)
Run Code Online (Sandbox Code Playgroud)
我真的想要一组相互递归的函数,它们只能改变 index我在main()函数中定义的变量,并且不能指向任何其他变量。
我已经阅读了变量名之前的“mut”和“:”之后的“mut”有什么区别?中的两个答案。,我已经尝试了几种方法,但仍然无法实现我想要的。我想我不太理解这些概念。
这是我目前理解的证据:
// with &mut I can change the referred value of n, but then I can't
// pass a mutable reference anywhere
fn mutate_usize_again(n: &mut usize) {
*n += 1;
// n += 70; ^ cannot use `+=` on type `&mut usize`
}
fn mutate_usize_two_times(mut n: &mut usize) {
*n = 8;
// if I don't write mut n, I can't pass a mutable reference to
// the mutate_usize_again function
mutate_usize_again(&mut n);
}
fn mutate_usize_one_time_referred_value(n: &mut usize) {
*n += 25;
}
// this changes the referred value of n
fn mutate_usize_one_time_mutable_pointer(mut n: usize) {
println!("n before assigning in mutate_usize_one_time = {}", n);
n = 48;
println!("n after assigning in mutate_usize_one_time = {}", n);
}
// doesn't work because of lifetimes
// this changes where is pointing a (Copy?) reference of n
// passed value does not change
/*
fn mutate_usize_one_time(mut n: &usize) {
println!("n before assigning in mutate_usize_one_time = {}", n);
n = &48;
println!("n after assigning in mutate_usize_one_time = {}", n);
}
*/
fn main() {
let mut index = 0;
mutate_usize_one_time_mutable_pointer(index);
println!("index after mutate_usize_one_time_mutable_pointer = {}", index);
mutate_usize_two_times(&mut index);
println!("index after mutate_usize_two_times = {}", index);
mutate_usize_one_time_referred_value(&mut index);
println!("index after mutate_usize_ = {}", index);
}
Run Code Online (Sandbox Code Playgroud)
如果我误解了,我真的很感激对我的代码中发生的事情的一个很好的解释。
我开始认为我想要的已经完成了:
index必须引用其更新值=>mut index index必须能够更改引用值并将可变引用传递给其他函数。=>&mut usize(mut index2: &mut usize),编译器不会让我有两个指向同一内存位置的可变引用。啊! 旧的指针/受指点问题。别担心,这是一个常见的绊脚石。坚持下去,到了某个时候,它就会发出咔嗒声,然后它就会变得显而易见。
什么是参考?
引用是一种间接。存在于其他地方的事物的地址。
我们打个比方:
目前,让我们忘记types、stack和heap:我们只有衣柜和抽屉:
注意:仅提及抽屉 ID 是无意义的,所有壁橱都有一个抽屉 0...
抽屉如何使用?
让我们想象一个(无类型)简单的例子,加法函数:
fn add(left, right) { left + right }
Run Code Online (Sandbox Code Playgroud)
现在,当我们调用 时会发生什么add(3, 4)?
Function
call
+-add-+ <-- New closet
| 3 | <-- Drawer 0: value 3
+-----+
| 4 | <-- Drawer 1: value 4
+-----+
Run Code Online (Sandbox Code Playgroud)
注意:在下文中,我将把衣柜表示为数组。这个壁橱将是[3, 4]。我还将使用字母对壁橱进行“编号”,以避免混合壁橱和抽屉,因此这个壁橱可能是d,而第一个抽屉d将是0@d(此处包含 3 个抽屉)。
该函数定义为“取出抽屉0中的值,取出抽屉1中的值,将它们添加到抽屉2中,返回抽屉2中的内容”。
让我们来调味吧;并介绍参考资料:
fn modify() {
let x = 42;
let y = &x;
*y = 32;
}
Run Code Online (Sandbox Code Playgroud)
有什么modify作用?
modify=> 给我们一个新的衣柜a: [],let x = 42;=> 我们的衣柜现在是a: [42],let y = &x;=> 我们的衣柜现在是a: [42, 0@a],现在关键来了:*y = 32;。这意味着将 32 放入 指向的抽屉中y。因此壁橱现在是:a: [32, 0@a]。
你的第一个例子
让我们看一下您的第一个示例,将其置于以下情况main:
// with &mut I can change the referred value of n, but then I can't
// pass a mutable reference anywhere
fn mutate_usize_again(n: &mut usize) {
*n += 1;
// n += 70; ^ cannot use `+=` on type `&mut usize`
}
fn main() {
let mut x = 24;
mutate_usize_gain(&mut x);
}
Run Code Online (Sandbox Code Playgroud)
那么,这是怎么回事?
main=>分配一个新的衣柜a: [],let mut x = 24;=> a: [24],mutate_usize_again=>分配一个新的衣柜b: [],&mut x=> b: [0@a],*n += 1;=> 将 1 添加到 (0@a) 指向的抽屉n,这意味着b没有改变,但是a确实改变了!现在a: [25]。n += 70=> 将 70 添加到引用中...这没有意义,引用没有算术运算。你的第二个例子
让我们继续讨论第二个示例(增强版):
// Parameter renamed because it's confusing to always use the same letter
fn mutate_usize_again(z: &mut usize) { *z += 1; }
fn mutate_usize_two_times(mut n: &mut usize) {
*n = 8;
// if I don't write mut n, I can't pass a mutable reference to
// the mutate_usize_again function
mutate_usize_again(&mut n);
}
fn main() {
let mut x = 24;
mutate_usize_two_times(&mut x);
}
Run Code Online (Sandbox Code Playgroud)
我们需要 3 个壁橱!
main=>分配一个新的衣柜a: [],let mut x = 24=> a: [24],mutate_usize_two_times=>分配一个新的衣柜b: [],n: &mut usize = &mut x=> b: [0@a],*n = 8n=> 将 8 存储在:指向的抽屉中a: [8],b不变,mutate_usize_again=>分配一个新的衣柜c: [],z: &mut usize = &mut n。&mut n的类型&mut &mut usize不能分配给类型 的参数z,z: &mut usize = n=> c: [0@a],*z += 1z=> 将:指向的抽屉中的值加 1 a: [9],b并且c保持不变。您可以引用参考,但这不是您在这里的本意。我们确实可以通过定义以下内容来扭曲该示例以使其正常工作:
fn mutate_usize_again(z: &mut &mut usize) { **z += 1; }
^ ^~~ dereference TWICE
|~~~~~~~~~~~~~~ two levels of reference
Run Code Online (Sandbox Code Playgroud)
在这种情况下,从调用重新开始mutate_usize_again:
a: [8]:b: [0@a]mutate_usize_again=>分配一个新的衣柜c: [],z: &mut &mut usize = &mut n=> c: [0@b]<- 引用到引用!**z += 1=> 将 所指向的引用所指向的抽屉中的值加 1 z。**z += 1is**0@b += 1是*0@a += 1,它修改a为 bea: [9]并保留bandc不变。你的第三个例子
您的第三个示例已增强:
fn mutate_usize_one_time_mutable_pointer(mut n: usize) {
println!("n before assigning in mutate_usize_one_time = {}", n);
n = 48;
println!("n after assigning in mutate_usize_one_time = {}", n);
}
fn main() {
let x = 42;
mutate_usize_one_time_mutable_pointer(x);
}
Run Code Online (Sandbox Code Playgroud)
我们走吧:
main=>分配一个新的衣柜a: [],let x = 42;=> a: [42],mutate_usize_one_time_mutable_pointer=> 分配一个新的壁橱b: []n: mut usize = x=> b: [42],n = 48n=> 修改:的值b: [48],注意a没有改变mutate_usize_one_time_mutable_pointer,丢弃b, a: [42]。这里没有涉及指针,函数的名称具有误导性。
你的最后一个例子
你的第四个例子,增强了:
fn mutate_usize_one_time(mut n: &usize) {
println!("n before assigning in mutate_usize_one_time = {}", n);
n = &48;
println!("n after assigning in mutate_usize_one_time = {}", n);
}
fn main() {
let x = 42;
mutate_usize_one_time(&x);
}
Run Code Online (Sandbox Code Playgroud)
我们走吧:
main=>分配一个新的衣柜a: [],let x = 42;=> a: [42],mutate_usize_one_time=>分配一个新的衣柜b: [],n: &size = &x=> b: [0@a],48=>b: [0@a, 48]&48=>b: [0@a, 48, 1@b]n = &48=> 会导致b: [1@b, 48]然而生命周期禁止引用指向过去的东西,这是被禁止的。希望它开始有意义。如果没有……那就去跑步,和朋友出去,清醒一下你的头脑,读另一个解释,再次清醒你的头脑,然后再回来。它会一点一点地渗透进去;)