【问题标题】:Why must callers use a constructor instead of creating a struct directly?为什么调用者必须使用构造函数而不是直接创建结构?
【发布时间】:2018-03-24 11:52:09
【问题描述】:

考虑以下 Rust sn-p from The Rust Programming Language, second edition

pub struct Guess {
    value: u32,
}

impl Guess {
    pub fn new(value: u32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }

        Guess {
            value
        }
    }

    pub fn value(&self) -> u32 {
        self.value
    }
}

和相应教程的评论,强调我的:

接下来,我们实现一个名为value的方法,它借用了self,没有任何 其他参数,并返回u32。有时这是一种方法 称为 getter,因为它的目的是从其字段中获取一些数据并 把它返还。这个公共方法是必要的,因为 value 的字段 Guess 结构是私有的。 value 字段是私有的,这一点很重要 使用Guess 结构的代码不允许直接设置value模块外的调用者必须使用Guess::new 函数来创建一个 Guess 的实例,确保 Guess 无法拥有 value 未被Guess::new 函数中的条件检查

为什么调用者必须使用new 函数?难道他们不能通过执行以下操作来绕过Guess.value 介于 1 到 100 之间的要求:

let g = Guess { value: 200 };

【问题讨论】:

  • 看高亮前的那句话:“重要的是值字段是私有的,这样使用Guess结构的代码就不能直接设置值”。
  • 难道他们不能绕过要求——你有没有尝试在模块之外编写一些“绕过要求”的代码?如果你有,你会很快看到阻止你的编译器错误。

标签: rust


【解决方案1】:

这仅适用于Guess 结构与使用它的代码在不同模块中定义的情况;结构本身是公开的,但它的value 字段不是,所以你不能直接访问它。

您可以通过以下示例 (playground link) 进行验证:

use self::guess::Guess;

fn main() {
    let guess1 = Guess::new(20); // works
    let guess2 = Guess::new(200); // panic: 'Guess value must be between 1 and 100, got 200.'
    let guess3 = Guess { value: 20 }; // error: field `value` of struct `guess::Guess` is private
    let guess4 = Guess { value: 200 }; // error: field `value` of struct `guess::Guess` is private
}

mod guess {
    pub struct Guess {
        value: u32,
    }

    impl Guess {
        pub fn new(value: u32) -> Guess {
            if value < 1 || value > 100 {
                panic!("Guess value must be between 1 and 100, got {}.", value);
            }

            Guess {
                value
            }
        }

        pub fn value(&self) -> u32 {
            self.value
        }
    }
}

本书解释了保持结构内容私有的基本原理。

【讨论】:

  • 相反,如果您想要Guess 值构造函数公开,您所要做的就是标记其所有成员 pub
猜你喜欢
  • 1970-01-01
  • 2020-11-15
  • 2015-06-10
  • 2012-06-28
  • 1970-01-01
  • 1970-01-01
  • 2017-09-04
  • 2013-04-25
相关资源
最近更新 更多