如何检查 Box 是否为空指针?

How to check if a Box is a null pointer?

我想用指针什么的实现一个栈。如何检查 Box 是否为空指针?我看到一些带有 Option<Box<T>>Box<Option<T>> 的代码,但我不明白这一点。这是我去的最远的地方:

struct Node {
    value: i32,
    next: Box<Node>,
}

struct Stack {
    top: Box<Node>,
}

Box<T> 永远不能为 NULL,因此无需检查。

Box<T> values will always be fully aligned, non-null pointers

std::box

您很可能希望使用 Option 来表示值的不存在/存在:

struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

struct Stack {
    top: Option<Box<Node>>,
}

另请参阅:

你不想要 nullnull 是一种不安全的反模式,即使在您 必须 使用它的语言中也是如此,幸运的是 Rust 让我们摆脱了这种暴行。 Box<T> always 包含 Tnever null。 Rust 没有 null.

的概念

正如您正确指出的那样,如果您希望某个值是可选的,请使用 Option<T>。你做 Box<Option<T>> 还是 Option<Box<T>> 真的没那么重要,对事情的底层了解多一点的人可以插话说哪个更有效率。

struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

struct Stack {
    top: Option<Box<Node>>,
}

Option 说“这可能存在也可能不存在”,Box 说“这个值在堆上。现在,Option 的好处就是它比 null 好得多的是你 来检查它。你 不能 忘记否则编译器会抱怨。典型的方式match

match my_stack.top {
    None => {
        // Top of stack is not present
    }
    Some(x) => {
        // Top of stack exists, and its value is x of type Box<T>
    }
}

Option 类型本身有 tons of helper methods 来处理常见的模式。下面只是我使用的一些最常用的。请注意,所有 都可以根据 match 实现,并且只是方便的功能。

相当于下面的Java代码

if (value == null) {
  result = null;
} else {
  result = ...;
}

let result = value.map(|v| ...)

或者,如果内部计算也可以产生 None

let result = value.and_then(|v| ...)

如果你想提供一个默认值,比如说零,比如

if (value == null) {
  result = 0;
} else {
  result = value;
}

那么你想要

result = value.unwrap_or(0)

最好停止思考如何处理 null 并从头开始学习 Option<T>。一旦掌握了它,它会感觉比 null 检查安全十倍,更符合人体工学。

A Box<T> 是指向堆上某个位置的指针,其中包含一些 T 类型的数据。 Rust 保证 Box<T> 永远不会是空指针,即只要你没有做任何奇怪的事情并且 unsafe.

地址应该总是有效的

如果你需要表示一个可能不存在的值(例如这个节点是最后一个节点,所以没有 next 节点),你可以像这样使用 Option 类型

struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

struct Stack {
    top: Option<Box<Node>>,
}

现在,对于 Option<Box<Node>>Node 可以有下一个 Node 或没有下一个节点。我们可以检查 Option 是否不是 None 这样的

fn print_next_node_value(node: &Node) {
    match &node.next {
        Some(next) => println!("the next value is {}", next.value),
        None => println!("there is no next node")
    }
}

因为 Box 只是指向堆上某个位置的指针,所以最好使用 Option<Box<T>> 而不是 Box<Option<T>>。这是因为第二个将在堆上分配一个 Option<T>,而第一个不会。此外,Option<Box<T>>Box<T> 同样大(均为 8 字节)。这是因为 Rust 知道 Box<T> 永远不可能全为零(即永远不可能是空指针),所以它可以使用全 0 的状态来表示 Option<Box<T>>None 情况.