我想定义几个类似的类型 struct A(Option)、struct B(Option) 等,其中浮点值被限制在一个范围内。这些结构的行为可能略有不同,但每种类型的构造函数都是相同的:如果值已经受到约束,则返回 Some(value),否则返回 None。 避免必须为每种类型单独实现每个构造函数;我想在特征中实现它。这真的不可能吗?
使用下面的代码,我被告知 Self 不是一个函数,我
can't use
Self
as a constructor, you must use the implemented struct
.
#[derive(Debug)]
struct A(Option<f64>);
trait Constrained {
const MIN: f64;
const MAX: f64;
fn is_constrained(value: f64) -> bool {
value >= Self::MIN && value <= Self::MAX
}
fn new(value: f64) -> Self where Self: std::marker::Sized {
if Self::is_constrained(value) {
Self(Some(value))
} else {
Self(None)
}
}
}
impl Constrained for A {
const MIN: f64 = -360.0;
const MAX: f64 = 360.0;
/*
fn new(value: f64) -> A {
if Self::is_constrained(value) {
Self(Some(value))
} else {
Self(None)
}
}
*/
}
fn main() {
let some_val: A = A::new(1000.0);
println!("{:?}", some_val);
}
注释掉特征中新函数的实现(从 where 之前开始),并取消注释每个单独结构的 impl 当然可行,但这会导致每种类型的代码不必要地加倍。 是否有任何可能或计划对此进行概括?
最佳答案
从你的代码来看,你似乎有几个要求:
- 实现结构必须为字段提供存储
Option<f64>
- 实现必须提供两个常量,MAX 和 MIN。
您真正要寻找的是结构上的 const 泛型。不幸的是,截至 2019 年 8 月,它仍然是一个高度不稳定且不完整的夜间功能。或者,您可以求助于宏。
derive_more
crate 允许你导出 From<Option<f64>>
对于每个只包含一个字段的实现结构元组。也就是说,您可能想要这样:
#[derive(From)]
pub struct A(Option<f64>);
// just a blanket impl with two consts
然后你的特征可以要求实现者也实现 From<Option<f64>>
,这是这里所需的构造函数:
pub trait Constrained : From<Option<f64>> {
const MAX: f64;
const MIN: f64;
// Your is_constrained method
// Use Self::from(None) instead of Self(None)
}
这会改进您在 From
中的尝试可以从现有宏自动派生(它也是 Rust 风格的惯用构造函数)。
重点是 Rust 特性不能对实现者的精确结构强加任何要求。某些实现者有另一个未使用的(或与 Constrained
无关的)字段也是有效的;那么你的trait不够灵活。
旁注:看起来您的特征将来可能不方便传递,因为特征常量项不是很灵活。也许您将来会希望使用示例宏来生成整个定义+impl。
关于function - 在 rust trait 中实现构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57440412/