在Rust中编写getter/setter属性

ajm*_*113 13 oop rust

我正在编写一个非常简单的getter/setting模型,我想在Rust中使用struct和出于简单的原因使用和impl.

struct Person {
    firstName: String,
    lastName: String,
}

impl Person {
    fn get_first_name(&mut self) -> String { return self.firstName; }
    fn get_last_name(&mut self) -> String {  return self.lastName; }

    fn set_first_name(&mut self, x: String) { self.firstName = x; }
    fn set_last_name(&mut self, x: String) { self.lastName = x; }

    fn default() -> Person {
        Person {firstName: "".to_string(), lastName: "".to_string()}
    }
}

fn main() {
    let mut my_person : Person = Person{ ..Person::default() };

    my_person.set_first_name("John".to_string());
    my_person.set_last_name("Doe".to_string());

    println!("{}", my_person.firstName);
    println!("{}", my_person.lastName);
}
Run Code Online (Sandbox Code Playgroud)

当我运行此代码段时,我收到以下错误.

src\main.rs:7:53: 7:57 error: cannot move out of borrowed content [E0507]
src\main.rs:7     fn get_first_name(&mut self) -> String { return self.firstName; }
                                                                  ^~~~
src\main.rs:8:53: 8:57 error: cannot move out of borrowed content [E0507]
src\main.rs:8     fn get_last_name(&mut self) -> String {  return self.lastName; }
                                                                  ^~~~
error: aborting due to 2 previous errors
Could not compile `sandbox`.
Run Code Online (Sandbox Code Playgroud)

有人可以向我指出这个错误,因为我对Rust很新吗?

有关更好地编写此代码段的提示也将被接受.我一直在寻找更容易/更快的可读性.

DK.*_*DK. 23

好的,这里的具体问题是无法摆脱借来的内容.这已经回答了 无数 之前在各种条件下,更不用提在锈图书所有权主体的章节.

更有趣的是吸气剂和二传手.是的,你可以用Rust写它们,但它们可能不是最好的选择.

在我继续之前,我只想注意,绝对没有理由要求&mut self使用getter ...除非你打算修改值作为删除值的一部分,但是那时你并没有真正处理任何getter更多.

其次,你不应该 clone在吸气器中.如果所有用户想要做的是例如从值中读取,那么这是非常浪费的.最好返回一个不可变的借位,clone 如果需要,用户可以从中借用.

无论如何,如果你正在写这些因为你想要某种逻辑运行以验证新值,那就继续使用setter.否则,你可以这样做:

#[derive(Default)]
struct Person {
    first_name: String,
    last_name: String,
}

impl Person {
    // Immutable access.
    fn first_name(&self) -> &String {
        &self.first_name
    }
    fn last_name(&self) -> &String {
        &self.last_name
    }

    // Mutable access.
    fn first_name_mut(&mut self) -> &mut String {
        &mut self.first_name
    }
    fn last_name_mut(&mut self) -> &mut String {
        &mut self.last_name
    }
}

fn main() {
    let mut my_person = Person::default();

    *my_person.first_name_mut() = String::from("John");
    *my_person.last_name_mut() = "Doe".into();

    println!("first_name: {}", my_person.first_name());
    println!("last_name: {}", my_person.last_name());

    // Can't do this efficiently with getter/setter!
    {
        let s = my_person.last_name_mut();
        s.truncate(2);
        s.push('w');
    }

    println!("first_name: {}", my_person.first_name());
    println!("last_name: {}", my_person.last_name());
}
Run Code Online (Sandbox Code Playgroud)

这为用户提供了或多或少的直接访问权限,而无需实际让他们直接访问这些字段.除了编写新值之外,这还允许用户就地改变现有值,这对于大量堆分配的东西很重要.

另外,我做了一些其他改动:

  • 你可以机械地推导出来Default; 在这种情况下没有理由自己写.

  • 传统风格适用snake_case于田野.

  • 你创建它的方式Person是不必要的回旋.

  • @ajm113 通常情况下,是的。*但是*,在这种情况下,您*还*可以对“String”进行可变访问,并且您可以使用“&String”做一件不能用“&str”做的事情:检查容量。另外,*一般来说*,两个指针的类型相同。 (2认同)
  • @DK。:将可变引用移交给您的领域而不是仅公开该领域有什么好处? (2认同)
  • @马蒂厄M。它为您购买的唯一东西是用户无法移出它,并且您可以随时更改它的存储位置。除此之外...... *耸耸肩* (2认同)

W.K*_*K.S 6

你的 getter 方法借用了self. 当您返回时self.name,您正在name从不允许的借用参考资料中移出。您应该返回 name 的副本。

此外,您不需要self在 getter 方法中传递可变引用,因为您没有修改内部结构。

因此,您的 getter 方法应该是:

fn get_first_name(&self) -> &String { &self.firstName }
fn get_last_name(&self) -> &String {  &self.lastName }
Run Code Online (Sandbox Code Playgroud)