在 mutagen 中,我正在对代码进行各种变异。其中一个我想要变异的模式是
if let Ok(x) = y { .. }
。然而,这带来了相当大的挑战,因为我无法知道 y
的类型 - 用户可能已经构建了自己的枚举,其中包含一个一元的 Ok
变体。对于实际上具有实现 Default
的错误类型的 Result
的情况,我仍然可以机会主义地进行变异,使用以下简化的 trait:#![feature(specialization)]
pub trait Errorer {
fn err(self, mutate: bool) -> Self;
}
impl<X> Errorer for X {
default fn err(self, _mutate: bool) -> Self {
self
}
}
impl<T, E> Errorer for Result<T, E>
where
E: Default,
{
fn err(self, mutate: bool) -> Self {
if mutate {
Err(Default::default())
} else {
self
}
}
}
唉,实现Default
的错误不是很多,所以这并不是太有用。即使对于Result<T,Box<Error>>
的实现也会更有帮助(并且完全可行)。然而,考虑到我并不太关心代码实际上检查错误,我想知道是否可以通过扩展上述代码的变异来进行一般实现。
match Errorer::err(y, mutation) {
Ok(x) => { .. }
Err(x) => { mem::forget(x); }
}
当进行变异时,err
返回 Err(mem::uninitialized())
,这种行为安全吗?注意:我从一个方法中返回 Err(mem::uninitialized())
,只是稍后使用 mem::forget
。我看不到任何可能导致崩溃的方式,因此我们应该假设该值确实被遗忘了。
这是定义良好的行为还是应该预期出现问题?
Option<Box<T>>
与Box<T>
的大小相同的技巧)。我不知道有没有影响Result
的任何布局优化,但我也看不到为什么不能在未来加入。如果是这种情况,mem::uninitialized
可能会使E
值处于无效状态,从而改变对Result
的解释。 - DK.Result<T, !>
可以(并且将来可能)与T
具有相同的布局。 - Stefan