看到一个小例子,是可以编译通过执行的。没想明白的是vec0变量,同时存在了不可变借用(第三行println! )和可变借用(第4行)。这不是跟rust的借用规则矛盾吗?借用规则是:同时存在一个可变借用,或多个不可变借用。我理解错了吗?
代码如下:
fn main () {
let mut vec0 = Vec::new();
println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);
let vec1 = fill_vec(&mut vec0);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: &mut Vec<i32>) -> &mut Vec<i32> {
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
1
共 8 条评论, 1 页
评论区
写评论第一句let mut vec0漏了mut,已改正。经过讨论,对printlin!的认识更清楚了,感谢各位大神耐心回答!
你可以把借用本身也看成一个变量,一个借用也是有其生命周期的,而对于println宏,其内部确实对vec0产生了一个不可变借用,但是这个借用在执行完这个宏块之后就无了,所以执行到后面产生可变借用的时候,vec0是不存在任何借用的,当然满足借用规则。
println! 展开后是一个block
首先你这个编译不过,是因为
let vec0 = Vec::new();
这里,vec0
是不可变变量,借不出可变引用&mut vec0
。不过这个是细枝末节的小问题。至于
println
,你可以把println!
当成是一个函数,你写进去的变量都会被它拿走一个不可变引用。而rust是移动语义,你借走了不可变引用,不可变引用权就进入了print
函数里,等到这个函数结束,不可变引用就drop
掉了。所以在let vec1 = fill_vec(&mut vec0);
,实际上已经没有引用了,所以可以借出不可变引用。当然也有可能
println
是生成了临时的不可变借用,由于没有绑定到变量上,所以句末就直接丢弃了。我不知道
println
是怎么运作的,但是我知道println
的行为就是,尝试借出不可变引用,打印后丢弃不可变引用。这是肯定的。此外还有一种你可能没发现的:
这种其实也是可行的,就是明明你持有不可变引用,但是后面
println
可以借出不可变引用。这是因为编译器会自动分析出,在println
之后是没有使用到可变引用vec1
的,所以就没问题。而在最后一行如果加上对vec1
的引用,编译器就会报错,这就是借用规则的体现了。--
👇
ziyouwa: 对vec0来说,最早应该是在第4行调用fill_vec之后才丢弃的
--
👇
eweca-d: 你这些都是临时借用,这一行结束后就丢弃了。
对vec0来说,最早应该是在第4行调用fill_vec之后才丢弃的
--
👇
eweca-d: 你这些都是临时借用,这一行结束后就丢弃了。
playground确实编译不过。 我在https://github.com/rust-lang/rustlings这个里面确实是通过了。exercises/move_semantics/move_semantics2.rs
这段代码一定编译不通过
Compiling playground v0.0.1 (/playground) error[E0596]: cannot borrow
vec0
as mutable, as it is not declared as mutable --> src/main.rs:6:26 | 2 | let vec0 = Vec::new(); | ---- help: consider changing this to be mutable:mut vec0
... 6 | let vec1 = fill_vec(&mut vec0); | ^^^^^^^^^ cannot borrow as mutableerror: aborting due to previous error
For more information about this error, try
rustc --explain E0596
. error: could not compileplayground
To learn more, run the command again with --verbose.
你这些都是临时借用,这一行结束后就丢弃了。