为什么 Rust 结构上未使用的类型参数被视为错误而不是警告?
Why are unused type parameters on Rust structs considered an error and not a warning?
在有人将其标记为重复之前,我知道如何修复它(并且已经回答过),但我想了解 为什么 存在此限制,但我在此处或 Rust 文档中没有找到答案。
例如,我写了这样的东西:
struct ItemList<T> {
items: Vec<T>
}
impl<T> ItemList<T> {
fn getFirstItem(&self) -> Link<T> { Link { position: 0 } }
}
struct Link<T> {
position: usize
}
impl<T> Link<T> {
fn getFromList<'a>(&self, list: &'a ItemList<T>) -> &'a T {
&list.items[self.position]
}
}
但是 rustc 拒绝了我的代码并出现以下错误:
error[E0392]: parameter `T` is never used
--> src/main.rs:8:13
|
8 | struct Link<T> {
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
For more information about this error, try `rustc --explain E0392`.
为什么这是错误而不是警告?类型参数只会降低编译时的性能(如果我理解正确的话),那么为什么要强制删除它或使用 PhantomData 标记呢?它是否有一些我错过的含义?
这是一个方差问题。
Rust 通过其用法来确定类型参数的变化。如果不使用类型,Rust 无法知道类型的变化。
加上@mcarton 所说的,从一开始就不是这样的:Rust 用于推断未使用的泛型参数是双变的。这在 2014 年发生了变化(在 Rust 1.0 之前)。 the RFC:
中解释了动机
Motivation
Today, variance inference for lifetimes includes the notion of bivariance -- which essentially amounts to unconstrained. In principle, this can have some use, but in practice it tends to be a vector for bugs. In fact, there is no known Rust code that intentionally uses bivariance (though there seems to be plenty that does so accidentally and incorrectly). This RFC proposes that we simply make an inference result of bivariance an error.
As an example of where this comes up, imagine a struct
with a "phantom" lifetime parameter, meaning one that is not actually used in the fields of the struct
itself. One example of such a type is Items
, the vector iterator:
struct Items<'vec, T> {
x: *mut T
}
Here the lifetime 'vec
is intended to represent the lifetime of the vector being iterated over and hence to prevent the iterator from outliving the container. However, because it does not appear in the body of Items
at all, the compiler would currently consider it irrelevant to subtyping. This means that you could convert from a Items<'a, T>
to a Items<'static, T>
, causing the iterator to outlive the container it is iterating over.
To prevent this scenario, the actual
definition of the iterator in the standard library uses a marker type. The marker type informs the compiler that, although 'vec
does not appear to be used, it should act as if it were. For example, Items
might be modified as follows:
struct Items<'vec, T> {
x: *mut T,
marker: marker::CovariantType<&'vec T>,
}
the CovariantType
marker basically informs the compiler that it should act "as though" a reference of type &'vec T
were a member of Items, even thought it is not. Another equivalent option here would be ContravariantLifetime
.
Currently, the user must know to insert these markers or else silently get the wrong behavior. This RFC makes it an error to have a type or lifetime parameter that is not (transitively) used somewhere in the type. Nothing else is changed.
代码很旧(例如 CovariantType
和 ContravariantLifetime
被 PhantomData
取代),但概念仍然适用。
在有人将其标记为重复之前,我知道如何修复它(并且已经回答过),但我想了解 为什么 存在此限制,但我在此处或 Rust 文档中没有找到答案。
例如,我写了这样的东西:
struct ItemList<T> {
items: Vec<T>
}
impl<T> ItemList<T> {
fn getFirstItem(&self) -> Link<T> { Link { position: 0 } }
}
struct Link<T> {
position: usize
}
impl<T> Link<T> {
fn getFromList<'a>(&self, list: &'a ItemList<T>) -> &'a T {
&list.items[self.position]
}
}
但是 rustc 拒绝了我的代码并出现以下错误:
error[E0392]: parameter `T` is never used
--> src/main.rs:8:13
|
8 | struct Link<T> {
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
For more information about this error, try `rustc --explain E0392`.
为什么这是错误而不是警告?类型参数只会降低编译时的性能(如果我理解正确的话),那么为什么要强制删除它或使用 PhantomData 标记呢?它是否有一些我错过的含义?
这是一个方差问题。
Rust 通过其用法来确定类型参数的变化。如果不使用类型,Rust 无法知道类型的变化。
加上@mcarton 所说的,从一开始就不是这样的:Rust 用于推断未使用的泛型参数是双变的。这在 2014 年发生了变化(在 Rust 1.0 之前)。 the RFC:
中解释了动机Motivation
Today, variance inference for lifetimes includes the notion of bivariance -- which essentially amounts to unconstrained. In principle, this can have some use, but in practice it tends to be a vector for bugs. In fact, there is no known Rust code that intentionally uses bivariance (though there seems to be plenty that does so accidentally and incorrectly). This RFC proposes that we simply make an inference result of bivariance an error.
As an example of where this comes up, imagine a
struct
with a "phantom" lifetime parameter, meaning one that is not actually used in the fields of thestruct
itself. One example of such a type isItems
, the vector iterator:struct Items<'vec, T> { x: *mut T }
Here the lifetime
'vec
is intended to represent the lifetime of the vector being iterated over and hence to prevent the iterator from outliving the container. However, because it does not appear in the body ofItems
at all, the compiler would currently consider it irrelevant to subtyping. This means that you could convert from aItems<'a, T>
to aItems<'static, T>
, causing the iterator to outlive the container it is iterating over.To prevent this scenario, the
actual
definition of the iterator in the standard library uses a marker type. The marker type informs the compiler that, although'vec
does not appear to be used, it should act as if it were. For example,Items
might be modified as follows:struct Items<'vec, T> { x: *mut T, marker: marker::CovariantType<&'vec T>, }
the
CovariantType
marker basically informs the compiler that it should act "as though" a reference of type&'vec T
were a member of Items, even thought it is not. Another equivalent option here would beContravariantLifetime
.Currently, the user must know to insert these markers or else silently get the wrong behavior. This RFC makes it an error to have a type or lifetime parameter that is not (transitively) used somewhere in the type. Nothing else is changed.
代码很旧(例如 CovariantType
和 ContravariantLifetime
被 PhantomData
取代),但概念仍然适用。