问题描述
我阅读了从头到尾,但我仍然对从数组到切片的强制转换有疑问。
让我们考虑以下代码:
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
。
数组强制转换为切片的条件是什么?我不了解前者和后者的代码之间的区别。
我还检查了,并猜测上述问题与引用的句子有关下面;
这种强制性旨在发挥作用,但不起作用
做没有实现 Deref
,因此强制& [T; n]-> & [T]
不是deref强制,因此其工作方式与deref强制相同。取而代之的是,它被称为超大强制。因为它将大小类型( [T; n]
)转换为无大小类型( [T]
)。 / p>
也就是说,,未完全支持的是套期保值;说未实现会更准确。因此,目前,通过传递性强制转换是完全不可能的。显然,此问题并不是一个高度优先的问题,可能是因为大小不大的阵列并不常见。 (我怀疑当const泛型登陆时,这可能会成为更常见的抱怨,因为这可能会使数组更有用。)
那为什么这样做 arr.first()
工作吗?好吧,用于查找用调用的方法。
(点)运算符是强制规则的扩展。 Autoderef类似于手动取消引用多次,直到使用给定方法获得某些内容(可以强制转换为某种类型)为止。这意味着您不需要传递性即可通过autoderef(RFC 401称为接收方强制)找到方法调用。
进一步阅读
描述了大多数强制的预期语义。该RFC已于5年前合并。从那时起,许多事情发生了变化,但仍然没有完全实现(其跟踪问题是),因此RFC 401无法准确地描述Rust的任何过去,现在或将来的版本。但是,RFC 401 也将允许强制&& [i32; 5]
到& [i32]
,并且逻辑几乎相同。
也有关于强制的一章,似乎与参考书一致。
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;
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):
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:
&[i32; 5]
coerces to&[i32]
by unsizing;&&[i32; 5]
coerces to&[i32; 5]
byDeref
;- therefore,
&&[i32; 5]
coerces to&[i32]
by transitivity. &&&[i32; 5]
coerces to&&[i32; 5]
byDeref
;- 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.
这篇关于为什么对数组的嵌套引用不会强制切片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!