【Rust 中级教程】 14 引用与借用(2)本篇文章将继续介绍 Rust 的引用,主要介绍一些引用的基本特征。本篇文章
0x00 开篇
本篇文章将继续介绍 Rust 的引用,主要介绍一些引用的基本特征。本篇文章的阅读时间大约 5 分钟。
0x01 println! 所有权?
本篇文章先来讨论一个问题,其实这也是大家比较关注的。
Q:println!
执行后变量为什么没有失去所有权?
要解开上面两个问题,我们搞清楚 println!
内部是如何执行的。println!
其实是一个宏,宏在编译时会扩展,被替换为其它 Rust 代码。(后续章节会详细介绍宏)想要看展开后的代码也很简单,只需要在源码根目录运行 cargo expand
先看这段代码:
fn main() {
let mut m = String::from("rust");
// 打印 m 和 n(没有解引用)
println!("m = {}", m);
// m 追加字符串(没有失去所有权)
m.push_str(" is easy.");
// 打印 m
println!("{}", m);
}
// 运行结果
// m = rust
// rust is easy.
我们在使用 println!
打印 m 时,m 并没有失去所有权, 执行下面的命令:
cargo expand
展开后的代码如下:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
let mut m = String::from("rust");
{
::std::io::_print(
::core::fmt::Arguments::new_v1(
&["m = ", "\n"],
// 传递了 &m
&[::core::fmt::ArgumentV1::new_display(&m)],
),
);
};
m.push_str(" is easy.");
{
::std::io::_print(
::core::fmt::Arguments::new_v1(
&["", "\n"],
// 传递了 &m
&[::core::fmt::ArgumentV1::new_display(&m)],
),
);
};
通过展开后的代码,可以看到 println!()
传递的是引用的值,所以它不会失去所有权了。但是如果你使用 dbg!
来打印变量的时候将会失去所有权,因为 dbg!
并没有获取参数的引用值,大家可以自行测试。
0x02 引用的引用
在 Rust 中允许 ”引用的引用“ 这种“套娃”存在。
fn main() {
let a: i32 = 4;
let b: &i32 = &a;
let c: &&i32 = &b;
let d: &&&i32 = &c;
println!("a = {}, b = {}, c = {}, d = {}", a, b, c, d);
struct Rectangle {
w: u32,
h: u32,
}
let x: Rectangle = Rectangle { w: 3, h: 4 };
let y: &Rectangle = &x;
let z: &&Rectangle = &y;
println!("x: w = {}, h = {}", x.w, x.h);
println!("y: w = {}, h = {}", y.w, y.h);
println!("z: w = {}, h = {}", z.w, z.h);
}
// 运行结果
// a = 4, b = 4, c = 4, d = 4
// x: w = 3, h = 4
// y: w = 3, h = 4
// z: w = 3, h = 4
上面的代码,我标注了类型,其实 Rust 是可以推断的,可以省略。不管“套娃”多少次, .
操作符,Rust 都可以找到他所引用的原始值。
0x03 引用的比较
fn main() {
let m = 1;
let n = 2;
let m1 = &m;
let n1 = &n;
// 比较
if m1 < n1 {
println!("m1 > n1");
}
// 下面的代码错误
// if m1 < n { }
}
// 运行结果
// m1 < n1
当引用比较时,无论 “套娃” 多少次,同样也可以使用最终指向的值进行比较。但是比较时一定要注意类型必须相同,Rust 不同的类型默认是无法比较的。如:m1 < n
这种语法是错误的,因为 m1
是 &i32
类型, n
是 i32
类型。
0x04 对表达式的引用
fn main() {
// 普通表达式
let x = &(8 + 78);
println!("x = {}", x);
// 闭包
let f = |h| h + 1;
let y = &f(1);
println!("y = {}", y);
// 函数
fn func_test(a: i32) -> i32 {
return a + 2;
}
let z = &func_test(3);
println!("y = {}", z);
}
// 运行结果
// x = 86
// y = 2
// y = 5
Rust 中允许对表达式进行引用。Rust 会创建一个匿名的变量来保存表达式的值,然后生成一个指向该值的引用。
0x05 小结
本篇文章主要介绍了 Rust 引用的一些特征属性,但是要注意的是,Rust 中引用永远不会为空。所以并不会存在类似其他语言的空指针的类型。本文介绍的内容相对简单,另外 println!
和 dbg!
对传参处理方法的不同也需要额外注意。
转载自:https://juejin.cn/post/7223043596621201464