练习题来自:https://practice-zh.course.rs/ownership/borrowing.html
1
fn main() {
let x = 5;
// 填写空白处
let p = __;
println!("x 的内存地址是 {:p}", p); // output: 0x16fa3ac84
}
其实Rust的借用,就类似C++的指针和引用,如果你有C++的基础,这道题就很好理解——取p的地址。
fn main() {
let x = 5;
// 填写空白处
let p = &x;
println!("x 的内存地址是 {:p}", p); // output: 0x16fa3ac84
}
2
fn main() {
let x = 5;
let y = &x;
// 只能修改以下行
assert_eq!(5, y);
}
对熟悉C++的同学来说,这道题也很好理解,&
用于取地址,而*
用于从地址取数据。
fn main() {
let x = 5;
let y = &x;
// 只能修改以下行
assert_eq!(5, *y);
}
3
// 修复错误
fn main() {
let mut s = String::from("hello, ");
borrow_object(s)
}
fn borrow_object(s: &String) {}
函数入参应该是String的借用(指针),而不是String本身。
fn main() {
let mut s = String::from("hello, ");
borrow_object(&s)
}
fn borrow_object(s: &String) {}
4
// 修复错误
fn main() {
let mut s = String::from("hello, ");
push_str(s)
}
fn push_str(s: &mut String) {
s.push_str("world")
}
和上面一样,不多解释了。
fn main() {
let mut s = String::from("hello, ");
push_str(&mut s)
}
fn push_str(s: &mut String) {
s.push_str("world")
}
5
fn main() {
let mut s = String::from("hello, ");
// 填写空白处,让代码工作
let p = __;
p.push_str("world");
}
应该是对s的可变引用。
fn main() {
let mut s = String::from("hello, ");
// 填写空白处,让代码工作
let p = &mut s;
p.push_str("world");
}
6
fn main() {
let c = '中';
let r1 = &c;
// 填写空白处,但是不要修改其它行的代码
let __ r2 = c;
assert_eq!(*r1, *r2);
// 判断两个内存地址的字符串是否相等
assert_eq!(get_addr(r1),get_addr(r2));
}
// 获取传入引用的内存地址的字符串形式
fn get_addr(r: &char) -> String {
format!("{:p}", r)
}
ref x = p
,就是x = &p
fn main() {
let c = '中';
let r1 = &c;
// 填写空白处,但是不要修改其它行的代码
let ref r2 = c;
assert_eq!(*r1, *r2);
// 判断两个内存地址的字符串是否相等
assert_eq!(get_addr(r1),get_addr(r2));
}
// 获取传入引用的内存地址的字符串形式
fn get_addr(r: &char) -> String {
format!("{:p}", r)
}
7
// 移除代码某个部分,让它工作
// 你不能移除整行的代码!
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
}
可变引用同时只能存在一个,因此都改成不可变即可(这样变量的mut
就没意义了)。
fn main() {
let mut s = String::from("hello");
let r1 = & s;
let r2 = & s;
println!("{}, {}", r1, r2);
}
8
fn main() {
// 通过修改下面一行代码来修复错误
let s = String::from("hello, ");
borrow_object(&mut s)
}
fn borrow_object(s: &mut String) {}
类似于C++里对变量声明const
和指针的关系一样(现在应该用constexpr
了)。常量只能使用常量指针,比如如下代码:
const int num = 1;
使用如下指针是不能指向num
的:
int *const p = #//p不可被更改,但p指向的数据,也就是num可以更改。这和num是const矛盾。此行代码会编译失败。
正确的写法是:
int const *p = #//虽然p本身可以被修改(比如可以指向别的数据),但p所指向的数据不可更改。
C++中的引用类似,只不过引用本身不是对象,所以没有改变这个概念,const
引用才能引用常量。
Rust也一样,s
不可变,那就不能有任何一个可变的引用借用s
。
fn main() {
// 通过修改下面一行代码来修复错误
let mut s = String::from("hello, ");
borrow_object(&mut s)
}
fn borrow_object(s: &mut String) {}
9
// 下面的代码没有任何错误
fn main() {
let mut s = String::from("hello, ");
borrow_object(&s);
s.push_str("world");
}
fn borrow_object(s: &String) {}
同上,不可变的引用指向可变的变量是可以的,但是这个引用不能拿来改变变量(即使变量可变)
10
// 注释掉一行代码让它工作
fn main() {
let mut s = String::from("hello, ");
let r1 = &mut s;
r1.push_str("world");
let r2 = &mut s;
r2.push_str("!");
println!("{}",r1);
}
r1
作为引用的作用域直到自身最后一次出现为止,因此,r2
刚好在r1
的作用域内,触发了不能同时存在两个可变引用的问题。注释掉最后一行,让r1
的作用域在第一次push就结束,就不会出现这个问题了。
fn main() {
let mut s = String::from("hello, ");
let r1 = &mut s;
r1.push_str("world");
let r2 = &mut s;
r2.push_str("!");
// println!("{}",r1);
}
11
fn main() {
let mut s = String::from("hello, ");
let r1 = &mut s;
let r2 = &mut s;
// 在下面增加一行代码人为制造编译错误:cannot borrow `s` as mutable more than once at a time
// 你不能同时使用 r1 和 r2
}
同上。
fn main() {
let mut s = String::from("hello, ");
let r1 = &mut s;
let r2 = &mut s;
r1.push_str("string");
// 在下面增加一行代码人为制造编译错误:cannot borrow `s` as mutable more than once at a time
// 你不能同时使用 r1 和 r2
}