【问题标题】:Writing getter/setter properties in Rust在 Rust 中编写 getter/setter 属性
【发布时间】:2016-02-14 10:14:10
【问题描述】:

我正在编写一个非常简单的 getter/setting 模型,为了简单起见,我想在 Rust 中使用 structimpl

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);
}

当我运行这个 sn-p 时,我收到以下错误。

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`.

由于我是 Rust 的新手,有人可以向我指出错误吗?

也可以接受更好地编写此 sn-p 的提示。我一直在寻找更容易/更快的可读性。

【问题讨论】:

  • 为什么你认为你需要getter和setter?为什么不struct Person { pub first_name: String, pub last_name: String, } 比较简单?
  • 请注意,有时 getter 和 setter 仍然有用,例如当您在特征中定义默认方法时,因为现在您无法定义/访问特征中的任何字段。见internals.rust-lang.org/t/fields-in-traits/6933

标签: oop rust


【解决方案1】:

好的,这里的具体问题是无法移出借来的内容。在各种条件下一直是answerednumeroustimesbefore,更不用说the chapter on the subject of ownership in the Rust Book了。

更有趣的是关于 getter 和 setter。是的,您可以用 Rust 编写它们,但它们可能不是最佳选择。

在我继续之前,我只想指出,绝对没有理由在 getter 上要求 &mut self...除非您打算修改该值作为删除值的一部分,但是你不再需要真正处理吸气剂了。

其次,您不应该 clone 在吸气剂中。如果用户想要做的只是例如从值中读取,这将是非常浪费的。最好返回一个不可变的借用,用户可以从中clone 如果他们需要。

无论如何,如果您编写这些代码是因为您希望运行某种逻辑来验证新值,请继续使用 setter。否则,你可以这样做:

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

impl Person {
    // Immutable access.
    fn first_name(&self) -> &str {
        &self.first_name
    }
    fn last_name(&self) -> &str {
        &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());
}

这让用户或多或少地直接访问这些字段,而实际上没有让他们直接访问这些字段。除了写入新值之外,这还允许用户就地改变现有值,这对于大型堆分配的事物可能很重要。

此外,我还做了一些其他更改:

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

  • 字段的常规样式是snake_case

  • 您创建Person 的方式是不必要的迂回。

【讨论】:

  • &str代替&String不是更正确吗?
  • @W.K.S,有趣的是我实际上有同样的问题。我记得读过一些类似使用 str 的东西,但我不记得了......
  • @ajm113 通常,是的。 但是,在这种情况下,您可以对String 进行可变访问,并且您可以使用&String 做一件您无法使用&String 做的事情&str:查看容量。另外,一般而言,这两个指针将属于同一类型。
  • @DK.:与仅仅公开该字段相比,将可变引用移交给您的字段有什么好处?
  • @MatthieuM。它给您带来的唯一好处是用户无法移出它,并且您可以随时更改它的存储位置。除此之外……耸耸肩
【解决方案2】:

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

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

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

fn get_first_name(&self) -> &str {
    self.first_name.as_str()
}
fn get_last_name(&self) -> &str {
    self.last_name.as_str()
}

【讨论】:

  • 您好,感谢您提供非常有帮助的反馈!直接做所有事情是有道理的,现在你这样说。显然,我来自一个非常沉重的 OOP 背景,使用 PHP/Java。所以在这种情况下,我需要开始考虑更简单的功能,在这种情况下,我大部分时间都需要做。除非我们正在讨论向结构添加功能。
猜你喜欢
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 2016-03-03
相关资源
最近更新 更多