#default #pseudo #swap #uninitialized

no-std orx-pseudo-default

PseudoDefault特质允许创建一个类型便宜默认实例,该实例不保证有用。

5个稳定版本

新版本 1.4.0 2024年8月13日
1.3.0 2024年8月13日
1.2.0 2024年7月25日
1.1.0 2024年7月25日
1.0.0 2024年7月23日

#375数据结构

Download history 212/week @ 2024-07-19 591/week @ 2024-07-26 776/week @ 2024-08-02 459/week @ 2024-08-09

2,038 每月下载量
用于 12 crates

MIT 许可证

25KB
63

orx-pseudo-default

orx-pseudo-default crate orx-pseudo-default documentation

PseudoDefault 特质允许创建一个类型便宜默认实例,该实例 不保证有用

PseudoDefaultDefault 的区别是对创建的实例有用性的期望更加宽松。

该特质的主要用例是在我们只需要创建一个不带任何参数的便宜实例时,之后将其丢弃。因此,创建的实例不需要是合适的。

此特质允许在某些用例中避免不安全代码。例如

  • 我们可以避免像uninit、手动drop等需要极其小心处理的技巧,实际上我们可以轻松创建一个有效的实例。
  • 当我们需要从一个无法实现Default的类型集合中取出元素时,我们可以使用伪默认来填补空白。

请注意,伪默认的要求比默认的要求更宽松,因此

  • 实现了Default的类型可以实现PseudoDefault
  • 此外,不能实现Default的类型可以手动实现PseudoDefault,前提是创建无参数的伪实例既安全又便宜。

示例

考虑以下虚构类型 Share,它将整体分割成块。如果没有提供 number_of_shares,则此类型没有意义。

因此,我们无法证明实现 Default 的合理性,这将是有误导性的。

如果我们仍然需要创建Share,我们可以简单地使用 pseudo_default。我们知道创建的类型不会保证行为上的合理性;然而,它仍然是一个便宜且有效的实例,可以被安全地丢弃。

use orx_pseudo_default::PseudoDefault;

struct Share {
    number_of_shares: std::num::NonZeroUsize,
}

impl Share {
    fn share_size(&self, whole_amount: usize) -> usize {
        whole_amount / self.number_of_shares
    }
}

impl PseudoDefault for Share {
    fn pseudo_default() -> Self {
        Self {
            number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
        }
    }
}

以下是一个更高级的使用案例。假设我们正在尝试创建一个名为 TakeVec 的vec包装器,具有以下特性:

  • 它允许通过名为 take 的方法通过索引取出元素
  • 我们应该能够包装已分配的vec而无需额外的分配
  • 我们需要能够返回原始分配的vec
  • 我们希望在不使用不安全代码的情况下实现这一点

使用 Default 可以轻松实现这一点,但我们需要对约束条件更宽松,以便它也能用于非默认类型。我们可以使用 PseudoDefault 来实现这一点。

use orx_pseudo_default::PseudoDefault;

struct TakeVec<T>(Vec<T>);

impl<T> From<Vec<T>> for TakeVec<T> {
    fn from(inner: Vec<T>) -> Self {
        Self(inner)
    }
}

impl<T> From<TakeVec<T>> for Vec<T> {
    fn from(value: TakeVec<T>) -> Self {
        value.0
    }
}

impl<T: PseudoDefault> TakeVec<T> {
    fn take(&mut self, index: usize) -> Option<T> {
        self.0.get_mut(index).map(|element| {
            let mut value = T::pseudo_default();
            std::mem::swap(&mut value, element);
            value
        })
    }
}

// implemented default types

let mut vec: TakeVec<_> = vec![0, 1, 2, 3].into();
assert_eq!(vec.take(2), Some(2));

let mut vec: TakeVec<_> = vec![0.to_string(), 1.to_string()].into();
assert_eq!(vec.take(0), Some(String::from("0")));

// non-default types

let mut vec: TakeVec<_> = vec![
    Share {
        number_of_shares: std::num::NonZeroUsize::new(42).unwrap(),
    },
    Share {
        number_of_shares: std::num::NonZeroUsize::new(7).unwrap(),
    },
]
.into();
assert_eq!(vec.take(0).map(|x| x.number_of_shares.into()), Some(42));

派生

Default 类似,只要所有成员也实现了 PseudoDefault,就可以派生 PseudoDefault

use orx_pseudo_default::*;

#[derive(PseudoDefault)]
struct ChildStruct {
    a: String,
    b: char,
    c: Vec<u32>,
}

#[derive(PseudoDefault)]
struct MyStruct {
    x: ChildStruct,
    y: bool,
    z: Option<usize>,
}

assert_eq!(String::pseudo_default(), MyStruct::pseudo_default().x.a);
assert_eq!(char::pseudo_default(), MyStruct::pseudo_default().x.b);
assert_eq!(Vec::<u32>::pseudo_default(), MyStruct::pseudo_default().x.c);
assert_eq!(bool::pseudo_default(), MyStruct::pseudo_default().y);
assert_eq!(
    Option::<usize>::pseudo_default(),
    MyStruct::pseudo_default().z
);

贡献

欢迎贡献!如果您发现错误,有问题或认为可以改进的地方,请打开问题或创建一个PR。

许可

此库在MIT许可下发布。有关详细信息,请参阅LICENSE。

依赖项

~105KB