我正在编写一个非常简单的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);
}
当我运行此代码段时,我收到以下错误。
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很新吗?
更好地编写此代码段的提示也将被接受。我一直在寻找更容易/更快的可读性。
答案 0 :(得分:19)
好的,这里的具体问题是无法摆脱借来的内容。在各种条件下,这一直是answered numerous times before,更不用说the chapter on the subject of ownership in the Rust Book了。
更有趣的是吸气剂和二传手。是的,您可以在Rust中编写它们,但它们可能不是最佳选择。
在我继续之前,我只想注意在getter上有绝对没有理由要求 4. 104ms for the JPEG and 177ms for the PNG
...除非您打算在删除过程中修改该值价值,但是你不再真正处理吸气剂了。
其次,你不应该在getter中 &mut self
。如果所有用户想要做的是例如从值中读取,那么这是非常浪费的。最好返回一个不可变的借位,如果需要,用户可以clone
。
无论如何,如果您正在编写这些文件是因为您希望运行某种逻辑以验证新值,请继续使用setter。否则,你可以这样做:
clone
这使用户可以或多或少地直接访问这些字段,而实际上可以直接访问这些字段。除了编写新值之外,这还允许用户就地改变现有值,这对于大量堆分配的东西很重要。
此外,我还做了一些其他改动:
你可以机械地推导#[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());
}
;在这种情况下没有理由自己写。
字段的常规样式为Default
。
您创建snake_case
的方式是不必要的回合。
答案 1 :(得分:1)
你的getter方法借用了self
。当您返回self.name
时,您将从借用的参考文件中移动name
,这是不允许的。您应该返回一份姓名副本。
此外,您不需要在getter方法中向self
传递可变引用,因为您没有修改内部结构。
因此,你的getter方法应该是:
fn get_first_name(&self) -> &String { &self.firstName }
fn get_last_name(&self) -> &String { &self.lastName }