在 rust trait 中实现构造函数
Implementing constructor function in rust trait
我想定义几个类似的类型 struct A(Option)、struct B(Option) 等,其中浮点值被限制在一个范围内。这些结构的行为可能略有不同,但每种类型的构造函数都是相同的:它 returns 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
那么你的 trait 可以要求实现者也实现 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。
我想定义几个类似的类型 struct A(Option)、struct B(Option) 等,其中浮点值被限制在一个范围内。这些结构的行为可能略有不同,但每种类型的构造函数都是相同的:它 returns 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
那么你的 trait 可以要求实现者也实现 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。