【问题标题】:How to check if a Box is a null pointer?如何检查 Box 是否为空指针?
【发布时间】:2021-07-02 10:43:22
【问题描述】:

我想使用指针或其他东西来实现堆栈。如何检查 Box 是否为空指针?我看到了一些带有Option<Box<T>>Box<Option<T>> 的代码,但我不明白这一点。这是我所到之处:

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

struct Stack {
    top: Box<Node>,
}

【问题讨论】:

    标签: pointers rust null box


    【解决方案1】:

    Box&lt;T&gt; 永远不能为 NULL,因此无需检查。

    Box&lt;T&gt; 值将始终完全对齐,非空指针

    ——std::box

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

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

    另见:

    【讨论】:

      【解决方案2】:

      你不想要nullnull 是一个不安全的反模式,即使在你必须使用它的语言中,幸好 Rust 让我们摆脱了暴行。 Box&lt;T&gt;总是包含T从不null。 Rust 没有null 的概念。

      正如您正确指出的那样,如果您希望某个值是可选的,请使用Option&lt;T&gt;。不管你是Box&lt;Option&lt;T&gt;&gt; 还是Option&lt;Box&lt;T&gt;&gt; 都没有那么重要,对底层事物有更多了解的人可以指出哪个更有效。

      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&lt;T&gt;。一旦掌握了窍门,它就会比null 检查更安全、更符合人体工学十倍。

      【讨论】:

      • 你能告诉我如何实现push和pop吗?
      • 这不适合 this 问题,尤其是考虑到您已经在 How do I implement a heap-based stack using Option<Box<T>>? 中提出过问题
      • 老实说,我的意思是真诚的,基于这个问题和 Shepmaster 链接的问题,我给你的最好建议是放慢速度并阅读一个好的 Rust 教程。似乎您期望 Rust 是“具有有趣语法的 C++”,但事实并非如此。这是一个完全不同的抽象方案,借用检查器在任何其他主流语言中都没有真正的等价物。像一个全新的范例一样接近它。它会创造奇迹。
      • 重新订购,首选Option&lt;Box&lt;T&gt;&gt;。以另一种方式完成动态分配,这样你就可以说你一无所有。由于 Box 永远不会为空,Option&lt;Box&lt;T&gt;&gt; 将使用空指针位模式来存储选项的None,免费。
      • "Rust 没有 null 的概念。" std::ptr::null?
      【解决方案3】:

      Box&lt;T&gt; 是指向堆上某个位置的指针,其中包含T 类型的一些数据。 Rust 保证 Box&lt;T&gt; 永远不会是空指针,即只要你没有做任何奇怪的事情和 unsafe,地址就应该始终有效。

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

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

      现在,有了Option&lt;Box&lt;Node&gt;&gt;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&lt;Box&lt;T&gt;&gt; 而不是Box&lt;Option&lt;T&gt;&gt;。这是因为第二个会在堆上分配一个Option&lt;T&gt;,而第一个不会。此外,Option&lt;Box&lt;T&gt;&gt;Box&lt;T&gt; 也同样大(均为 8 字节)。这是因为 Rust 知道 Box&lt;T&gt; 永远不能全为零(即永远不能是空指针),所以它可以使用全 0 的状态来表示 Option&lt;Box&lt;T&gt;&gt;None 情况。

      【讨论】:

      • Nitpick:即使你 正在 做一些奇怪的事情并且 unsafe, Box&lt;T&gt; 仍然 不允许为空指针, true 以外的任何一个都可以是 false。如果您编写的代码尝试创建一个空 Box,则行为未定义,并且任何事情都可能发生:包括 Box 实际上 not 为空。所以unsafe 与其说是一个例外,不如说是一个额外的约束。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-05
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多