首页 > 解决方案 > 防止直接初始化类型别名

问题描述

我目前正在学习 rust 并偶然发现了一个我不知道如何解决的问题。

我想要一个类型(称为Guess),这i32仅限于某个数字范围(在下面的示例中介于 1 和 100 之间)。我目前的解决方案是使用实现new函数的类型别名来强制数字范围。仍然可以通过正常初始化创建它,而不使用Guess::new(),因为没有像结构中那样的私有字段。

这可以防止吗?还应防止直接更改该值。

代码示例(操场):

type Guess = i32;

trait G {
    fn new(val: i32) -> Guess;
}

impl G for Guess {
    fn new(val: i32) -> Guess {
        if val < 1 || val > 100 {
            panic!("Only guesses between 1 and 100 are allowed!");
        }
        val
    }
}

fn main() {
    let guess: Guess = 23; // should not be allowed
    let guess: Guess = Guess::new(42); // only this should be allowed
    println!("Guess this number: {}", guess);
}

标签: rust

解决方案


正如其他人所说,您要做的是使用“newtype”模式,它基本上是将您的类型包装成另一个:

struct Guess(i32);

impl Guess {
    fn new(val: i32) -> Self {
        assert!(val >= 1 && val <= 100,
            "Only guesses between 1 and 100 are allowed!");
        Self(val)
    }
}

fn main() {
    //let guess: Guess = 23; // this is an error now
    let guess: Guess = Guess::new(42); // fine
    println!("Guess this number: {}", guess.0);
}

主要区别在于用户将需要使用guess.0.


还有其他一些改进:

  • 不需要一个特征来定义方法。
  • 使用Self避免了类型名的重复。
  • assert!对于if+ panic!

推荐阅读