在 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。