对比Rust引用与C++引用
Contents
前言
最近在学习 Rust , Rust 中也有引用,这让我有点好奇 Rust 的引用是不是与 C++ 一样,于是便有了此文。
变量的引用
C++
先来看看 C++ 中变量的引用
int a = 1;
int& ref = a;
std::cout << "a的地址: " << &a << std::endl;
std::cout << "引用ref的地址: " << &ref << std::endl;
结果如下:
| a的地址: | 0x7ff7b28663e8 |
|---|---|
| 引用ref的地址: | 0x7ff7b28663e8 |
可以看到引用 ref 的地址和 a 的地址一模一样,所以在 C++ 中 引用只是个别名 和原来没什么区别。
Rust
let a: i32 = 1;
let refa: &i32 = &a;
println!("a的地址: {:p}", &a);
println!("引用refa的地址 :{:p}", &refa);
结果如下:
a的地址: 0x7ff7ba577df4
引用refa的地址 :0x7ff7ba577df8
可以看到引用 refa 的地址与 a 地址不同。也就是 refa 有它自己的地址,所以 Rust 的引用更像是指针,指针有它自己的地址,但是它们指向的内存是同一块。传递引用就是赋值,不可变引用是 Copy 语义。也就是通常说的值拷贝。
我们尝试把引用的内容打出来看下,猜测应该就是 a 地址
let a: i32 = 1;
let refa: &i32 = &a;
println!("a的地址: {:p}", &a);
println!("引用refa的地址: {:p}", &refa);
println!("引用refa指向值: {:p}", refa);
结果如下:
a的地址: 0x7ff7b677e1fc
引用refa的地址: 0x7ff7b677e1a8
引用refa指向值: 0x7ff7b677e1fc
从上面的结果中发现引用 refa 的内容(指向的地址)和 a 的地址一样,也就是它们指向同一块内存。而引用 refa 本身有它自己的地址。
引用作为函数参数
C++
依照惯例依旧先看下 C++ 中函数中使用引用作为参数的情况
void test(int& a) {
std::cout << "引用a的地址: " << &a << std::endl;
}
int main(int argc, char *argv[])
{
int a = 1;
std::cout << "a的地址: " << &a << std::endl;
test(a);
return 0;
}
结果如下:
| a的地址: | 0x7ff7b7cad3dc |
|---|---|
| 引用a的地址: | 0x7ff7b7cad3dc |
函数调用的情况下 C++ 中引用的地址始终如一。没有发生变量的拷贝。
Rust
接下来看 Rust 中函数使用引用作为参数的情况
fn test(a: &i32) {
println!("参数a的地址: {:p}", &a);
println!("参数a的指向的地址: {:p}", a);
}
fn main() {
let a: i32 = 1;
let refa: &i32 = &a;
println!("a的地址: {:p}", &a);
println!("refa的地址: {:p}", &refa);
test(&a);
}
结果如下:
a的地址: 0x7ff7bb8bb1ac
refa的地址: 0x7ff7bb8bb1a0
参数a的地址: 0x7ff7bb8bb198
参数a的指向的地址: 0x7ff7bb8bb1ac
在 Rust 的函数中引用的地址与函数外面的引用 refa 都不一样,所以 Rust 中的引用更像是值传递而不是引用传递(相对C++而言)。
严格的说 Rust 的引用并不是真的引用,而是值拷贝。
总结
Rust中的不可变引用实现的是Copy语义,在发生变量赋值、参数传递的情况下会发生拷贝。Rust可变引用没有实现Copy语义,发生赋值会转移所有权。Rust的引用不像C++中引用,更像是指针。Rust的引用与Golang中引用更像。