当 T 未实现克隆时,为什么无法为通用选项克隆 None<T>?

  • 本文关键字:None 选项 实现 generics rust clone
  • 更新时间 :
  • 英文 :


给定一个具有泛型Option<T>的结构,其中T可能无法实现Clone为什么不能克隆NoneT类型的None不是和任何其他None一样吗?例如:

struct Foo<T> {
bar: Vec<Option<T>>,
}
impl <T> Foo<T> {
fn blank(size: usize) -> Foo<T> {
Foo {
bar: vec![None; size],
}
}
}

由于其他答案正确指出了 ouf,这是由于vec!-macro 的实现方式。您可以手动创建任何Option<T>Vec,而无需CloneT

let bar = std::iter::repeat_with(|| Option::<T>::None).take(size).collect::<Vec<_>>();

这将创建size数量的Option::<T>::None并将它们放在一个Vec中,该将被预先分配到适当的大小。这适用于任何T

T类型的None与任何其他None不同吗?

绝对不是!与基于引用的语言不同,在基于引用的语言中,null 通常在内部表示为 null 指针(地址为 0 的指针),Rust 的Option<T>不引入间接寻址,并在Some选项时内联存储T。由于所有枚举变体都具有枚举的类型,因此大小相同,因此None变体仍必须至少占用与T一样多的空间。

话虽如此,从技术上讲,None值可以在不CloneT的情况下克隆,这仅仅是因为枚举的None变体不包含T,它只存储鉴别器并保留可能包含T的空间,如果变体要更改为Some。但是由于 Rust 枚举变体不是单独的类型,因此为枚举定义的特征绑定必须涵盖所有变体。

请参阅其他答案 更详细的解释和说明 如何创建不可克隆OptionNone值向量 。

如果无法克隆一个部分,则无法克隆任何部分。从类型的角度考虑这个问题:你有一个名为fooOption<T>类型的变量,其中T不可克隆。当然,None可以克隆,但Some(_)不能,变量的类型不会告诉你它是哪个。因此,从编译时的角度来看,您无法克隆该选项。

只有当内部T实现Clone时,才能克隆Option

impl<T> Clone for Option<T>
where
T: Clone, 

T类型的None不是和任何其他None一样吗?

其实不然。Rust 编译器甚至不None视为一种类型。相反,None只是Option<T>的一个变体(子类型)。尝试比较两个不同TNones:

let a: Option<String> = None;
let b: Option<u8> = None;
assert_eq!(a, b)

您将看到它们实际上是完全不相关的类型:

error[E0308]: mismatched types
--> src/main.rs:4:5
|
4 |     assert_eq!(a, b)
|     ^^^^^^^^^^^^^^^^ expected struct `String`, found `u8`
|
= note: expected enum `Option<String>`
found enum `Option<u8>`

所以 Rust 编译器实际上认为NoneOption::<T>::None。这意味着如果T不是Clone,那么Option<T>不是Clone,因此Option::<T>::None不能被Clone

要使代码编译,必须将T约束为Clone

struct Foo<T: Clone> {
bar: Vec<Option<T>>,
}
impl <T: Clone> Foo<T> {
fn blank(size: usize) -> Foo<T> {
Foo {
bar: vec![None; size],
}
}
}

现在编译器知道TClone,并且Option<T>(和Option::<T>::None)的Clone实现已经实现。

如果项目数不是太大,以至于如果放置在其上会使堆栈溢出,则可以从数组构造Vec。数组的优点是它们可以从const值构造,即使类型不是Copy

const NONE: Option<NonClone> = None;
Vec::from([NONE; 10])

最新更新