【问题标题】:How to validate struct creation? [duplicate]如何验证结构创建? [复制]
【发布时间】:2020-12-20 00:23:40
【问题描述】:

我正在处理Rust by Example。我目前在TryFrom and TryInto。这是他们的代码:

struct EvenNumber(i32);

impl TryFrom<i32> for EvenNumber {
    type Error = ();

    fn try_from(value: i32) -> Result<Self, Self::Error> {
        if value % 2 == 0 {
            Ok(EvenNumber(value))
        } else {
            Err(())
        }
    }
}

该实现阻止创建具有奇数的EvenNumber 实例,但前提是我调用try_from(或try_into)。我仍然可以直接创建EvenNumber(1337)

在 Java(和相关语言)中,可以在构造函数中验证实例创建,例如:

class EvenNumber {
    public final int value;

    public EvenNumber(int value) {
        if (value % 2 != 0) {
            throw new IllegalArgumentException("value is odd");
        }
        this.value = value;
    }
}

如何在 Rust 中做到这一点?

【问题讨论】:

    标签: validation struct rust


    【解决方案1】:

    您可以在某个模块中定义 EvenNumber 并将其 num 字段保密,因此人们创建 EvenNumber 实例的唯一方法是通过您控制的公共方法,例如 new。示例:

    mod some_mod {
        pub struct EvenNumber {
            num: i32,
        }
        
        impl EvenNumber {
            pub fn new(num: i32) -> Result<Self, ()> {
                if num % 2 == 0 {
                    Ok(EvenNumber {
                        num,
                    })
                } else {
                    Err(())
                }
            }
        }
    }
    
    // bring EvenNumber into scope
    use some_mod::EvenNumber;
    
    fn try_to_create_invalid_even_number() -> EvenNumber {
        EvenNumber {
            num: 1337, // compile error
        }
    }
    

    投掷:

    error[E0451]: field `num` of struct `EvenNumber` is private
      --> src/lib.rs:24:9
       |
    24 |         num: 1337,
       |         ^^^^^^^^^ private field
    

    playground

    【讨论】:

    • 似乎合乎逻辑。我还没有到达模块章节。但是如何从模块外部访问num?我必须写一个吸气剂吗?
    • @xehpuk 差不多
    【解决方案2】:

    当您的元组结构在不同的模块中定义时(可以只是不同的文件)或如下所示:

    mod mod_name {
        #[derive(Debug)]
        pub struct EvenNumber(i32);
        
        use std::convert::TryFrom;
        impl TryFrom<i32> for EvenNumber {
            type Error = ();
    
            fn try_from(value: i32) -> Result<Self, Self::Error> {
                if value % 2 == 0 {
                    Ok(EvenNumber(value))
                } else {
                    Err(())
                }
            }
        }
    }
    
    fn main() {
        // let num = mod_name::EvenNumber(5); // error[E0603]: tuple struct constructor `EvenNumber` is private
        
        use std::convert::TryFrom;
        let num = mod_name::EvenNumber::try_from(4);
        println!("num = {:?}", num.unwrap());
    }
    

    那么您将无法使用任何数字直接构造该元组。您可以通过取消注释上面示例中的注释行来测试这一点。在 Rust 中,实体的隐私只对兄弟模块或父模块很重要,而对同一个范围或子模块无关。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-04
      • 2016-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多