标准库的链接列表Node uses the Option type:

struct Node<T> {
    next: Option<NonNull<Node<T>>>,
    prev: Option<NonNull<Node<T>>>,
    element: T,
}

并使用以下代码创建一个 node :

Node {
    next: None,
    prev: None,
    element,
}

BTreeLeafNode的实现,标准库uses a raw pointer for the parent node:

struct LeafNode<K, V> {
    parent: *const InternalNode<K, V>,
    parent_idx: MaybeUninit<u16>,
    len: u16,
    keys: MaybeUninit<[K; CAPACITY]>,
    vals: MaybeUninit<[V; CAPACITY]>,
}

并创建新的叶 node by setting parent to ptr::null:

LeafNode {
    keys: MaybeUninit::uninitialized(),
    vals: MaybeUninit::uninitialized(),
    parent: ptr::null(),
    parent_idx: MaybeUninit::uninitialized(),
    len: 0
}

我们可以用nullptr来实现C++中的上述代码,那么Optionstd::ptr::null()之间的区别是什么?建议用什么方式表示空指针?

推荐答案

一般来说,我建议使用NonNull<T>除以*const T*mut T,根据情况使用Option来确定指针何时可能为空.

原因有两个:

  1. null是否为有效值,在使用NonNull时会被记录和enforced.
  2. *const T*mut T基本上是可互换的,实际上可以相互转换,因此constmut可能会提供错误的安全感.

BTree的实现可能根本没有被移植到NonNull,这是相对较新的——它只在1.25中稳定下来.

Rust相关问答推荐

什么是谓词的简短和简洁类型

如何在Rust中获得不可辩驳的'if let'模式警告Mutex锁定?""

如何用Axum/Tower压缩Html内容?

什么时候和为什么S最好是按值或引用传递简单类型

在IntoIter上调用.by_ref().Take().rev()时会发生什么情况

`*mut[T]`与`*mut T`的区别

如何使用Actix Web for Rust高效地为大文件服务

为什么AsyncRead在Box上的实现有一个Unpin特征绑定?

通过异常从同步代码中产生yield 是如何工作的?

我应该如何表达具有生命周期参数的类型的总排序,同时允许与不同生命周期进行比较?

如何执行数组文字的编译时串联?

使用启用优化的 alloc 会导致非法指令崩溃

为什么 Rust 需要可变引用的显式生命周期而不是常规引用?

通过mem::transmute将数组展平安全吗?

(let b = MyBox(5 as *const u8); &b; ) 和 (let b = &MyBox(5 as *const u8); ) 之间有什么区别

Rust:`sort_by` 多个条件,冗长的模式匹配

仅当函数写为闭包时才会出现生命周期错误

Rust 生命周期:这两种类型声明为不同的生命周期

在线程中运行时,TCPListener(服务器)在 ip 列表中的服务器实例之前没有从客户端接受所有客户端的请求

覆盖类型的要求到底是什么?为什么单个元素元组满足它?