Rust——智能指针的概念
指针基本上是存储另一个变量地址的变量。虽然智能指针是行为类似于传统指针的数据类型,但具有其他功能,例如自动内存管理或边界检查。
智能指针与普通指针的不同之处在于:-
- 它们是结构体,包含额外的元数据和功能。
- 他们不借用数据,而是拥有数据。
是什么让智能指针与结构不同:-
- 它们实现了Deref和Drop特性。
Deref trait 允许智能指针结构的实例表现得像一个引用,这样处理指针的代码也可以处理智能指针。
Drop trait 允许我们自定义当智能指针的实例超出范围时应该运行的代码。
一些智能指针是:-
- Box
在堆上分配值 - Rc
一种支持多重所有权的引用计数类型
盒子
Box 允许我们将数据存储在堆中,这与 Rust 存储为堆栈的默认方案相反。
Box 主要用于:
- 用于为变量动态分配内存。
- 当有大量数据需要转移所有权时,我们不希望它们被复制。
让我们创建一个盒子来在堆中存储 i32 值
Rust
fn main() {
let num = Box::new(4);
println!("num = {}", num);
}
Rust
enum List {
Cons(i32, List),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}
Rust
#[derive(Debug)]
enum List {
Cons(i32, Box),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
println!("{:?}",list)
}
Rust
struct CustomPointer(T);
impl CustomPointer {
fn new(x: T) -> CustomPointer {
CustomPointer(x)
}
}
Rust
struct CustomPointer(T);
impl CustomPointer {
fn new(x: T) -> CustomPointer {
CustomPointer(x)
}
}
//implementing deref trait
use std::ops::Deref;
impl Deref for CustomPointer {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let x = 5;
let y = CustomPointer::new(x);
println!("{}",x==5);
println!("{}",*y==5);
}
Rust
// defining custom smart pointer
struct CustomPointer (T);
impl CustomPointer {
fn new(x: T) -> CustomPointer {
CustomPointer(x)
}
}
use std::ops::Deref;
// for implementing deref trait
impl Deref for CustomPointer {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// for implementing drop trait
impl Drop for CustomPointer {
fn drop(&mut self) {
println!("Dropping CustomtPointer with data");
}
}
fn main() {
let x = 5;
let y = CustomPointer::new(x);
println!("{}",x==5);
println!("{}",*y==5);
}
输出
num = 4
使用 Box
我们将使用 cons list 创建一个值列表。 cons list 取值第一个是当前值,另一个是下一个值,它执行对 cons函数的递归调用以生成一个列表,其中递归调用的基本条件是 Nil。
锈
enum List {
Cons(i32, List),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}
它不会编译,因为在编译之前无法确定 List 变量大小。
输出:
rustc -o main main.rs
error[E0072]: recursive type `List` has infinite size
--> main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^ recursive type has infinite size
2 | Cons(i32, List),
| ---- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable
error[E0391]: cycle detected when processing `List`
--> main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^
|
= note: ...which again requires processing `List`, completing the cycle
= note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: List } }`
有一个错误告诉 List 具有无限大小,因为编译器在编译期间无法确定 List 的大小。所以我们将使用指向列表的指针而不是列表本身来克服这个错误。由于指针的大小是固定的,与它指向的数据类型无关,因此编译器可以在编译期间确定其大小。让我们看看这个使用 Box
锈
#[derive(Debug)]
enum List {
Cons(i32, Box),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
println!("{:?}",list)
}
输出:
Cons(1, Cons(2, Cons(3, Nil)))
定义我们自己的智能指针:
锈
struct CustomPointer(T);
impl CustomPointer {
fn new(x: T) -> CustomPointer {
CustomPointer(x)
}
}
在这里,我们将自定义智能指针定义为一个具有一个值的元组结构。我们定义了一个新方法,它在智能指针被实例化时被调用,它返回一个自定义的智能指针。
在我们的自定义智能指针上使用取消引用特征:
就像普通的指针一样,我们可以通过使用'*'运算符来获取盒子的值。
锈
struct CustomPointer(T);
impl CustomPointer {
fn new(x: T) -> CustomPointer {
CustomPointer(x)
}
}
//implementing deref trait
use std::ops::Deref;
impl Deref for CustomPointer {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let x = 5;
let y = CustomPointer::new(x);
println!("{}",x==5);
println!("{}",*y==5);
}
输出:
true
true
在我们的智能指针上使用 Drop trait:
每当智能指针的实例超出范围时,就会调用 drop函数。
锈
// defining custom smart pointer
struct CustomPointer (T);
impl CustomPointer {
fn new(x: T) -> CustomPointer {
CustomPointer(x)
}
}
use std::ops::Deref;
// for implementing deref trait
impl Deref for CustomPointer {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// for implementing drop trait
impl Drop for CustomPointer {
fn drop(&mut self) {
println!("Dropping CustomtPointer with data");
}
}
fn main() {
let x = 5;
let y = CustomPointer::new(x);
println!("{}",x==5);
println!("{}",*y==5);
}
输出:
true
true
Dropping CustomtPointer with data