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

jte*_*epe 9 rust

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

fn mold_slice<'a, T>(_: &'a T) -> &'a [T] {
    &[]
}
Run Code Online (Sandbox Code Playgroud)

我想到了这是怎么可能的,因为这里的"值"基本上存在于函数的堆栈框架中,但签名承诺返回对具有更长生命周期的值的引用('a包含函数调用).我得出的结论是,因为空数组[]是一个ZST,它基本上只是静态存在.编译器可以"伪造"引用所引用的值.

所以我尝试了这个:

fn mold_unit<'a, T>(_: &'a T) -> &'a () {
    &()
}
Run Code Online (Sandbox Code Playgroud)

然后编译器抱怨:

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 () {
  |                                         ^
Run Code Online (Sandbox Code Playgroud)

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

struct Empty;

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

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

游乐场的例子

DK.*_*DK. 5

不是[]大小为零(虽然是零),而是[]常量,编译时文字。这意味着编译器可以将其存储在可执行文件中,而不必在堆或堆栈上动态分配它。反过来,这意味着指向它的指针可以持续所需的时间,因为可执行文件中的数据不会随处可见。

烦人,这不会扩展到类似&[0],因为锈是不是聪明地认识到[0]绝对不变的。您可以使用以下方法解决此问题:

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

这招也可与任何你可以把一个const()Empty

实际上,实际上,像这样的函数返回&'static借用会更简单,因为可以自动将其强制到任何其他生存期。

编辑:以前的版本指出&[]大小不是零,这有点切线。