rust - 对零大小类型的引用之间的生命周期差异

标签 rust

我在玩零尺寸类型 (ZST) 时遇到了一个有趣的案例。对空数组的引用将塑造成具有任何生命周期的引用:

fn mold_slice<'a, T>(_: &'a T) -> &'a [T] {
    &[]
}

我考虑过这是怎么可能的,因为这里的“值”基本上存在于函数的堆栈帧中,但签名 promise 返回对具有更长生命周期的值的引用 ('a 包含函数调用)。我得出的结论是,这是因为空数组 [] 是一个基本上只静态存在的 ZST。编译器可以“伪造”引用所指的值。

所以我尝试了这个:

fn mold_unit<'a, T>(_: &'a T) -> &'a () {
    &()
}

然后编译器报错:

error: borrowed value does not live long enough
 --> <anon>:7:6
  |
7 |     &()
  |      ^^ temporary value created here
8 | }
  | - temporary value only lives until here
  |
note: borrowed value must be valid for the lifetime 'a as defined on the block at 6:40...
 --> <anon>:6:41
  |
6 | fn mold_unit<'a, T>(_: &'a T) -> &'a () {
  |                                         ^

它不适用于单元 () 类型,也不适用于空结构:

struct Empty;

// fails to compile as well
fn mold_struct<'a, T>(_: &'a T) -> &'a Empty {
    &Empty
}

不知何故,单元类型和空结构与空数组的处理方式不同。除了只是 ZST 之外,这些值之间还有其他区别吗?这些差异(&[] 适合任何生命周期而 &()&Empty 不适合)与 ZST 完全无关吗?

Playground example

最佳答案

并不是说 [] 是零大小的(尽管它是),而是说 [] 是一个常量,编译时文字。这意味着编译器可以将它存储在可执行文件中,而不必在堆或堆栈上动态分配它。反过来,这意味着指向它的指针可以随心所欲地持续存在,因为可执行文件中的数据不会去任何地方。

恼人的是,这并没有扩展到像 &[0] 这样的东西,因为 Rust 不是相当聪明到可以意识到 [0]绝对 常量。您可以使用类似的方法解决此问题:

fn mold_slice<'a, T>(_: &'a T) -> &'a [i32] {
    const C: &'static [i32] = &[0];
    C
}

这个技巧也适用于 任何 你可以放在 const 中,比如 ()Empty

但实际上,让像这样的函数返回一个&'static 借用会更简单,因为它可以自动强制转换为任何其他 生命周期。

编辑:之前的版本注意到 &[] 不是零大小,这有点离题。

关于rust - 对零大小类型的引用之间的生命周期差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41898890/

相关文章:

rust - 使用状态机模式时解决 Rust 所有权问题

regex - 将所有正则表达式匹配捕获到一个向量中

unix - 通过将 ctrl-c 发送到标准输入来将 SIGINT 发送到进程

utf-8 - 作为 16 位切片的格式错误的 UTF-8 的 WTF-8 字符串集

generics - trait 不能做成一个对象

rust - Near-bindgen宏: unsupported argument type

rust - 如何在保持对特征对象的引用的同时具有特征对象的向量

rust - 如何将 Vec<Vec<f64>> 的元素加在一起成为 Vec<f64>?

function - Rust 函数如何修改数组索引的值?

rust - 如何在嵌入式平台中将 u32 数据转换为 &str?