为什么对数组的嵌套引用不会强制切片? [英] Why doesn't a nested reference to an array coerce to a slice?

查看:265
本文介绍了为什么对数组的嵌套引用不会强制切片?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



让我们考虑以下代码:

  let arr:& [i32; 5] =&& [1、2、3、4、5]; 
// //让arr:& [i32] =&& [1、2、3、4、5]; //错误;预期切片,找到参考

我希望&& [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强制,因此其工作方式与deref强制相同。取而代之的是,它被称为超大强制。因为它将大小类型( [T; n] )转换为无大小类型( [T] )。 / p>

也就是说,语言参考(不是规范性的,可能已经过时,但请允许我)列出了可能的强制,包括以下内容(添加了强调):



  • T_1 T_3 ,其中 T_1 强制为 T_2 T_2 强制为 T_3 transitive case


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



  • & T & U 如果 T 实现 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] 强制为& [i32; 5] 通过 Deref ;

  3. ,因此,& [i32 ; 5] 通过传递性强制到& [i32]

  4. & ;& [i32; 5] 强制为&& [i32; 5] 通过 Deref ;

  5. ,因此,&& [i32; 5] 通过传递性强制到& [i32]

但是不是。上面的引用暗示了为什么:在传递情况下,它说注意,这还没有被完全支持。据我所知,根据 issue#18602 ,未完全支持的是套期保值;说未实现会更准确。因此,目前,通过传递性强制转换是完全不可能的。显然,此问题并不是一个高度优先的问题,可能是因为大小不大的阵列并不常见。 (我怀疑当const泛型登陆时,这可能会成为更常见的抱怨,因为这可能会使数组更有用。)


那为什么这样做 arr.first()工作吗?好吧,自动引用规则 用于查找用调用的方法。(点)运算符是强制规则的扩展。 Autoderef类似于手动取消引用多次,直到使用给定方法获得某些内容(可以强制转换为某种类型)为止。这意味着您不需要传递性即可通过autoderef(RFC 401称为接收方强制)找到方法调用。




进一步阅读


RFC#401 描述了大多数强制的预期语义。该RFC已于5年前合并。从那时起,许多事情发生了变化,但仍然没有完全实现(其跟踪问题是#18469 ),因此RFC 401无法准确地描述Rust的任何过去,现在或将来的版本。但是,RFC 401 将允许强制&& [i32; 5] & [i32] ,并且逻辑几乎相同。


Rustonomicon 也有关于强制的一章,似乎与参考书一致。


I read What are Rust's exact auto-dereferencing rules? from beginning to end, but I still have a question about the coercion from array to slice.

Let us think about the following code:

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

I would expect that &&&[1, 2, 3, 4, 5] has the type, &&&[i32; 5] and dereferences to &&[i32; 5] => &[i32; 5] => &[i32; 5] => &[i32], but the result is different from what I expected.

I tried to run the following code:

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

That's the correct code. The type of arr is coerced to &&&[i32; 5] => &&[i32; 5] => &[i32; 5] => &[i32] and matches to the first argument of first in slice, &self.

What's the condition that arrays coerce to slices? I don't understand the difference between the former and the latter code.

I also checked the documentation in the source code, and guess that the above question has something to do with the sentence cited below;

However we sometimes do other adjustments and coercions along the way, in particular unsizing (e.g., converting from [T; n] to [T]).`

解决方案

This kind of coercion is intended to work, but not implemented.

Arrays do not implement Deref, so the coercion &[T; n] -> &[T] is not a deref coercion and does not work in quite the same way as one. Instead, it's called an "unsized coercion" because it turns a sized type ([T; n]) into an unsized one ([T]).

That said, the language reference (which is not normative and may be outdated, but bear with me) lists the possible coercions, including the following (emphasis added):

  • T_1 to T_3 where T_1 coerces to T_2 and T_2 coerces to T_3 (transitive case)

    Note that this is not fully supported yet

  • &T to &U if T implements Deref<Target = U>.

  • TyCtor(T) to TyCtor(U), where TyCtor(T) is one of

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

    and where T can be obtained from U by unsized coercion.

The last bullet, unsized coercion, is what allows &[T; n] to coerce to &[T]. Notably, this only describes one layer of referencing; it doesn't cover the &&[T; n] -> &[T] case (for which we also need Deref coercion).

Back to your non-working example:

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

The intended coercion is &&&[i32; 5] -> &[i32]. We can work out how this coercion ought to work:

  1. &[i32; 5] coerces to &[i32] by unsizing;
  2. &&[i32; 5] coerces to &[i32; 5] by Deref;
  3. therefore, &&[i32; 5] coerces to &[i32] by transitivity.
  4. &&&[i32; 5] coerces to &&[i32; 5] by Deref;
  5. therefore, &&&[i32; 5] coerces to &[i32] by transitivity.

But it doesn't. The quote above hints at why: under the transitive case, it says "Note that this is not fully supported yet". As far as I can tell, according to issue #18602, "not fully supported" is a hedge; it would be more accurate to say "unimplemented". So, for now, coercion via transitivity is not possible at all. Apparently this issue is not a high priority, probably because sized arrays aren't very common. (I suspect this might become a more common complaint when const generics land, since that may make arrays more useful.)

So why does arr.first() work? Well, the "auto-dereferencing rules" used to find methods invoked with the . (dot) operator are an extension of the coercion rules. Autoderef is similar to manually dereferencing any number of times until you get something (that can be coerced to a type) with the given method. This means you don't need transitivity to find method calls through autoderef (which RFC 401 calls "receiver coercion").


Further reading

RFC #401 describes intended semantics of most coercions. This RFC was merged over 5 years ago. Many things have changed since then, but it is still not fully implemented (its tracking issue is #18469), so RFC 401 does not accurately describe any past, present, or future version of Rust. Nevertheless, RFC 401 also would permit coercion of &&&[i32; 5] to &[i32] and by almost the same logic.

The Rustonomicon also has a chapter on coercions and appears to agree with the reference book.

这篇关于为什么对数组的嵌套引用不会强制切片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆