为什么对数组的嵌套引用不会强制转换为切片?
Why doesn't a nested reference to an array coerce to a slice?
我从头到尾读了,但我对从数组到切片的强制转换仍有疑问。
让我们思考下面的代码:
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]
=> [=17 的取消引用=],
但是结果和我预想的不一样
我试过运行下面的代码:
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
.
数组强制切片的条件是什么?看不懂前者和后者代码的区别
我也查了the documentation in the source code,猜测上面的问题和下面引用的句子有关系;
However we sometimes do other adjustments and coercions along the way, in particular unsizing (e.g., converting from [T; n] to [T]).`
这种强制是为了工作,但没有实施。
Arrays 没有实现 Deref
,所以强制转换 &[T; n] -> &[T]
不是一个 deref 强制转换,并且工作方式与一个完全不同。相反,它被称为“未调整大小的强制转换”,因为它将调整大小的类型 ([T; n]
) 转换为未调整大小的类型 ([T]
)。
也就是说,language reference(这不是规范的,可能已经过时了,但请耐心等待)列出了可能的强制转换,包括以下内容(强调已添加):
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
or &mut 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 U
can be obtained from T
by unsized coercion.
最后一个项目符号,unsized 强制转换,允许 &[T; n]
强制转换为 &[T]
。值得注意的是,这只描述了一层引用;它不包括 &&[T; n]
-> &[T]
案例(为此我们还需要 Deref
强制)。
回到你的非工作示例:
let arr: &[i32] = &&&[1, 2, 3, 4, 5];
预期的强制转换是 &&&[i32; 5]
-> &[i32]
。我们可以弄清楚这种强制应该如何工作:
&[i32; 5]
通过缩小大小强制转换为 &[i32]
;
&&[i32; 5]
通过 Deref
; 强制转换为 &[i32; 5]
- 因此,
&&[i32; 5]
通过传递性强制转换为 &[i32]
。
&&&[i32; 5]
通过 Deref
; 强制转换为 &&[i32; 5]
- 因此,
&&&[i32; 5]
通过传递性强制转换为 &[i32]
。
但事实并非如此。上面的引用暗示了原因:在传递情况下,它说“请注意,这还没有得到完全支持”。据我所知,根据 issue #18602,“未完全支持”是一种对冲;说“未实现”会更准确。因此,就目前而言,通过传递性进行强制转换根本不可能。显然这个问题不是一个高优先级,可能是因为大小数组不是很常见。 (我怀疑当 const 泛型出现时,这可能会成为更常见的抱怨,因为这可能会使数组更有用。)
那么为什么 arr.first()
有效?好吧,用于查找使用 .
(点)运算符调用的方法的 与强制转换规则不同。 Autoderef 类似于手动取消引用任意次数,直到您使用给定的方法得到某些东西(可以强制转换为一种类型)。这意味着您不需要传递强制来通过 autoderef 查找方法调用。
进一步阅读
RFC #401 describes intended semantics of most coercions, but has never been fully implemented. Issue #18602 跟踪传递强制的状态。
Rustonomicon 也有一章是关于强制转换的,似乎与参考书一致。
我从头到尾读了
让我们思考下面的代码:
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]
=> [=17 的取消引用=],
但是结果和我预想的不一样
我试过运行下面的代码:
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
.
数组强制切片的条件是什么?看不懂前者和后者代码的区别
我也查了the documentation in the source code,猜测上面的问题和下面引用的句子有关系;
However we sometimes do other adjustments and coercions along the way, in particular unsizing (e.g., converting from [T; n] to [T]).`
这种强制是为了工作,但没有实施。
Arrays 没有实现 Deref
,所以强制转换 &[T; n] -> &[T]
不是一个 deref 强制转换,并且工作方式与一个完全不同。相反,它被称为“未调整大小的强制转换”,因为它将调整大小的类型 ([T; n]
) 转换为未调整大小的类型 ([T]
)。
也就是说,language reference(这不是规范的,可能已经过时了,但请耐心等待)列出了可能的强制转换,包括以下内容(强调已添加):
T_1
toT_3
whereT_1
coerces toT_2
andT_2
coerces toT_3
(transitive case)Note that this is not fully supported yet.
&T
or&mut T
to&U
ifT
implementsDeref<Target = U>
.TyCtor(
T
) to TyCtor(U
), where TyCtor(T
) is one of
&T
&mut T
*const T
*mut T
Box<T>
and where
U
can be obtained fromT
by unsized coercion.
最后一个项目符号,unsized 强制转换,允许 &[T; n]
强制转换为 &[T]
。值得注意的是,这只描述了一层引用;它不包括 &&[T; n]
-> &[T]
案例(为此我们还需要 Deref
强制)。
回到你的非工作示例:
let arr: &[i32] = &&&[1, 2, 3, 4, 5];
预期的强制转换是 &&&[i32; 5]
-> &[i32]
。我们可以弄清楚这种强制应该如何工作:
&[i32; 5]
通过缩小大小强制转换为&[i32]
;&&[i32; 5]
通过Deref
; 强制转换为 - 因此,
&&[i32; 5]
通过传递性强制转换为&[i32]
。 &&&[i32; 5]
通过Deref
; 强制转换为 - 因此,
&&&[i32; 5]
通过传递性强制转换为&[i32]
。
&[i32; 5]
&&[i32; 5]
但事实并非如此。上面的引用暗示了原因:在传递情况下,它说“请注意,这还没有得到完全支持”。据我所知,根据 issue #18602,“未完全支持”是一种对冲;说“未实现”会更准确。因此,就目前而言,通过传递性进行强制转换根本不可能。显然这个问题不是一个高优先级,可能是因为大小数组不是很常见。 (我怀疑当 const 泛型出现时,这可能会成为更常见的抱怨,因为这可能会使数组更有用。)
那么为什么 arr.first()
有效?好吧,用于查找使用 .
(点)运算符调用的方法的
进一步阅读
RFC #401 describes intended semantics of most coercions, but has never been fully implemented. Issue #18602 跟踪传递强制的状态。
Rustonomicon 也有一章是关于强制转换的,似乎与参考书一致。