为什么在这个例子中&[u8]
和&[u8; 3]
都可以?
fn main() {
let x: &[u8] = &[1u8, 2, 3];
println!("{:?}", x);
let y: &[u8; 3] = &[1u8, 2, 3];
println!("{:?}", y);
}
&[T; n]
可以胁迫&[T]
的事实是让他们容忍的方面。 — Chris Morgan
为什么&[T; n]
强迫&[T]
?在其他条件下,这种强制发生了吗?
[T; n]
是一个长度为n
的数组,表示为邻近n
实例的T
。
&[T; n]
纯粹是对该数组的引用,表示为指向数据的精简指针。
[T]
是一个切片,一个未分类型;它只能通过某种形式的间接使用。
&[T]
,称为切片,是一种大小的类型。它是一个胖指针,表示为指向第一个项目和切片长度的指针。
因此,阵列在编译时已知其长度,而切片长度是运行时问题。数组是目前Rust中的二等公民,因为不可能形成数组泛型。有[T; 0]
,[T; 1]
等的各种特征的手动实现,通常最多32个;由于这种限制,切片通常更有用。 &[T; n]
可以胁迫&[T]
的事实是让他们容忍的方面。
有fmt::Debug
的[T; 3]
的实施,其中T
实施Debug
,&T
实施T
的fmt::Debug
,u8
实施Debug
,&[u8; 3]
也实现&[T; n]
。
为什么
&[T]
强迫&[T]
?在Rust,强制何时发生?
它会在需要时强制执行,而且不会在其他时间强制执行。我可以想到两个案例:
&[T; n]
,你给它一个x.starts_with(…)
它会默默地胁迫;[T; n]
上调用[T; n]
时,它会发现在&[T; n]
上没有这样的方法,所以autoref进入游戏并尝试&[T]
,这没有帮助,然后强制发挥作用,它尝试starts_with
,它有一个称为[1, 2, 3].starts_with(&[1, 2])
的方法。片段&[T; n]
演示了两者。
为什么
&[T]
强迫&[T; n]
?
另一个答案解释了为什么&[T]
应该强迫&[T; n]
,在这里我将解释编译器如何解决&[T]
可以胁迫four possible coercions in Rust。
有T
:
U
强迫U
和V
胁迫T
,那么V
强迫&mut T
。&T
→*mut T
和*const T
→&mut T
转换为原始指针:*mut T
→&T
和*const T
→Deref
traitT: Deref<Target = U>
:
如果&T
,那么&U
通过deref()
方法强制到T: DerefMut
(同样地,如果&mut T
,那么&mut U
通过deref_mut()
强制到Unsize
trait)Ptr
:
如果&T
是一个“指针类型”(例如*mut T
,Box
,Rc
,T: Unsize<U>
等)和Ptr<T>
,那么Ptr<U>
强迫Unsize
。
[T; n]: Unsize<[T]>
特性自动实现为:
T: Unsize<Trait>
T: Trait
在哪里struct Foo<…> { …, field: T }: Unsize< struct Foo<…> { …, field: U }>
T: Unsize<U>
,前提是Ptr<X>
(以及一些使编译器工作更容易的条件)
(Rust认为CoerceUnsized
是一种“指针类型”,如果它实现了T: CoerceUnsized<U>
。实际规则被称为“如果T
然后U
强迫&[T; n]
”。)&[T]
强制执行impl Unsize<[T]> for [T; n]
的原因是规则4:(a)编译器为每个[T; n]
生成实现&X
,并且(b)参考&[T; n]
是指针类型。使用这些,&[T]
可以胁迫。
qazxswpoi
我根据@Shepmaster和Chris Morgan的回答粘贴了一张便条图,描述了不同的概念。