为什么对数组的嵌套引用不强制到切片?



我从头到尾阅读了 Rust 的确切自动取消引用规则是什么? 但我仍然对从数组到切片的强制有疑问。

让我们考虑以下代码:

let arr: &[i32; 5] = &&&[1, 2, 3, 4, 5];
// let arr: &[i32] = &&&[1, 2, 3, 4, 5]; // Error; expected slice, found reference

我希望&&&[1, 2, 3, 4, 5]具有类型,&&&[i32; 5]和取消引用&&[i32; 5]=>&[i32; 5]=>&[i32; 5]=>&[i32], 但结果与我的预期不同。

我尝试运行以下代码:

let arr: &&&[i32; 5] = &&&[1, 2, 3, 4, 5];
let n = arr.first().unwrap(); // 1

这是正确的代码。arr的类型被强制为&&&[i32; 5]=>&&[i32; 5]=>&[i32; 5]=>&[i32]并与切片中first的第一个参数匹配,&self

数组强制切片的条件是什么?我不明白前者代码和后代码之间的区别。

我还检查了源代码中的文档,猜测上面的问题与下面引用的句子有关;

然而,我们有时会在此过程中进行其他调整和强制,特别是调整大小(例如,从 [T; n] 转换为 [T])。

这种强制是有效的,但不是实现的。

数组不实现Deref,所以强制&[T; n] -> &[T]不是deref强制,并且与强制工作方式不同。相反,它被称为"未调整大小的强制",因为它将大小的类型([T; n])变成未大小的类型([T])。

也就是说,语言参考(不是规范性的,可能已经过时,但请耐心等待)列出了可能的胁迫,包括以下内容(着重号是后加的):

  • T_1T_3,其中T_1胁迫T_2T_2胁迫T_3(传递案例)

    请注意,尚不完全支持此功能。

  • &T&mut T&UT是否实现了Deref<Target = U>

  • TyCtor(T) 到 TyCtor(
  • U),其中 TyCtor(T) 是其中之一

    • &T
    • &mut T
    • *const T
    • *mut T
    • Box<T>

    以及可以通过不大范围的胁迫从T获得U

最后一颗子弹,不大威压,是允许&[T; n]胁迫&[T]的原因.值得注意的是,这仅描述了一层引用;它不包括&&[T; n]->&[T]的情况(我们还需要Deref胁迫)。

回到你的非工作示例:

let arr: &[i32] = &&&[1, 2, 3, 4, 5];

预期的胁迫是&&&[i32; 5]->&[i32]。我们可以弄清楚这种胁迫应该如何运作:

  1. &[i32; 5]通过调整大小来强制&[i32];
  2. &&[i32; 5]胁迫Deref&[i32; 5];
  3. 因此,&&[i32; 5]通过传递性胁迫&[i32]
  4. &&&[i32; 5]胁迫Deref&&[i32; 5];
  5. 因此,&&&[i32; 5]通过传递性强制&[i32]

但事实并非如此。上面的引用暗示了原因:在传递情况下,它说"请注意,这还没有完全支持"。据我所知,根据问题 #18602,"不完全支持"是一种对冲;说"未执行"会更准确。因此,就目前而言,通过传递性进行强制根本不可能。显然,这个问题不是一个高优先级的问题,可能是因为大小的数组不是很常见。(我怀疑当常量泛型登陆时,这可能会成为更常见的抱怨,因为这可能会使数组更有用。

那么arr.first()为什么有效呢?好吧,用于查找使用.(点)运算符调用的方法的"自动取消引用规则"与强制规则不同。Autoderef 类似于手动取消引用任意次数,直到您使用给定方法获得某些内容(可以强制转换为类型)。这意味着您不需要传递强制来通过 autoderef 查找方法调用。


延伸阅读

RFC #401 描述了大多数强制的预期语义,但从未完全实现。问题 #18602 跟踪传递强制的状态。

Rustonomicon也有一章是关于胁迫的,似乎同意参考书。

相关内容

  • 没有找到相关文章

最新更新