我对Rust非常非常新,并尝试实现一些简单的东西来感受语言。现在,我绊倒了实现类似类的结构的最佳方法,该结构涉及将字符串转换为int。我正在使用一个全局命名空间的函数,我的Ruby大脑感觉不对。
这样做的乡土方式是什么?
use std::io;
struct Person {
name: ~str,
age: int
}
impl Person {
fn new(input_name: ~str) -> Person {
Person {
name: input_name,
age: get_int_from_input(~"Please enter a number for age.")
}
}
fn print_info(&self) {
println(fmt!("%s is %i years old.", self.name, self.age));
}
}
fn get_int_from_input(prompt_message: ~str) -> int {
println(prompt_message);
let my_input = io::stdin().read_line();
let my_val =
match from_str::<int>(my_input) {
Some(number_string) => number_string,
_ => fail!("got to put in a number.")
};
return my_val;
}
fn main() {
let first_person = Person::new(~"Ohai");
first_person.print_info();
}
这会编译并具有所需的行为,但我不知道该怎么做 - 显然我不了解最佳实践或如何实现它们。
编辑:这是0.8
答案 0 :(得分:8)
以下是我的代码版本,我更加惯用了这个代码:
use std::io;
struct Person {
name: ~str,
age: int
}
impl Person {
fn print_info(&self) {
println!("{} is {} years old.", self.name, self.age);
}
}
fn get_int_from_input(prompt_message: &str) -> int {
println(prompt_message);
let my_input = io::stdin().read_line();
from_str::<int>(my_input).expect("got to put in a number.")
}
fn main() {
let first_person = Person {
name: ~"Ohai",
age: get_int_from_input("Please enter a number for age.")
};
first_person.print_info();
}
fmt!
/ format!
首先,Rust使用基于fmt!
的语法弃用printf
宏,而使用format!
,它使用类似于Python format strings的语法。新版本的Rust 0.9会抱怨使用fmt!
。因此,您应该将fmt!("%s is %i years old.", self.name, self.age)
替换为format!("{} is {} years old.", self.name, self.age)
。但是,我们有一个方便的宏println!(...)
,这意味着与println(format!(...))
完全相同,所以在Rust中编写代码的最惯用方法是
println!("{} is {} years old.", self.name, self.age);
对于像Person
这样的简单类型,在Rust中使用struct literal语法创建该类型的实例是惯用的:
let first_person = Person {
name: ~"Ohai",
age: get_int_from_input("Please enter a number for age.")
};
如果您确实需要构造函数,Person::new
是类型Person
的“默认”构造函数(我指的是最常用的构造函数)的惯用名。但是,默认构造函数要求从用户输入初始化似乎很奇怪。通常,我认为您将拥有person
模块(例如,模块导出person::Person
)。在这种情况下,我认为使用模块级函数fn person::prompt_for_age(name: ~str) -> person::Person
是最惯用的。或者,您可以在Person
- Person::prompt_for_age(name: ~str)
上使用静态方法。
&str
与~str
我已将get_int_from_input
的签名更改为&str
而不是~str
。 ~str
表示在交换堆上分配的字符串 - 换句话说,C中的malloc
/ free
或C ++中的new
/ delete
的堆操作。但是,与C / C ++不同,Rust强制要求交换堆上的值一次只能由一个变量拥有。因此,将~str
作为函数参数意味着函数的调用者不能重用它传入的~str
参数 - 它必须复制{{1}使用~str
方法。
另一方面,.clone
是字符串的切片,它只是对字符串中一系列字符的引用,因此它不需要在分配字符串的新副本时调用具有&str
参数的函数。
在&str
中对&str
使用~str
而不是prompt_message
的原因是该函数不需要保留超过函数末尾的消息。它仅使用提示消息进行打印(而println
需要get_int_from_input
,而不是&str
。更改函数以~str
后,您可以将其称为&str
而不是get_int_from_input("Prompt")
,这样可以避免在堆上不必要地分配get_int_from_input(~"Prompt")
(同样,您也可以可以避免在下面的代码中克隆"Prompt"
:
s
let s: ~str = ~"Prompt";
let i = get_int_from_input(s.clone());
println(s); // Would complain that `s` is no longer valid without cloning it above
// if `get_int_from_input` takes `~str`, but not if it takes `&str`.
Option<T>::expect
方法是您拥有的匹配语句的惯用快捷方式,如果您获得Option<T>::expect
,则要返回x
,如果获得Some(x)
,则返回失败1}}。
None
在Rust中,它是惯用的(遵循Haskell和OCaml等函数式语言的示例)返回值而不显式编写return
语句。实际上,函数的返回值是函数中最后一个表达式的结果,除非表达式后跟一个分号(在这种情况下它返回return
,也就是单位,这实际上是一个空的占位符值 - ()
也是没有显式返回类型的函数返回的内容,例如()
或main
)。
我无论如何都不是Rust的伟大专家。如果您需要有关Rust的任何帮助,除了Stack Overflow之外,您还可以尝试使用irc.mozilla.org上的#rust IRC频道或Rust subreddit。
答案 1 :(得分:0)
这并不是特定的生锈特性,但尝试将功能拆分为离散单元。不要混淆在终端上放置字符串的低级任务,以及从终端获取字符串以及更直接相关(并且在很大程度上依赖于实现)的请求值的任务,并验证它。当你这样做时,你应该开始做出的设计决定。
例如,你可以写下这样的东西(我还没有编译它,而且我是自己生锈的新手,所以他们可能至少有一件事是错的:))
fn validated_input_prompt<T>(prompt: ~str) {
println(prompt);
let res = io::stdin().read_line();
loop {
match res.len() {
s if s == 0 => { continue; }
s if s > 0 {
match T::from_str(res) {
Some(t) -> {
return t
},
None -> {
println("ERROR. Please try again.");
println(prompt);
}
}
}
}
}
}
然后将其用作:
validated_input_prompt<int>("Enter a number:")
或:
validated_input_prompt<char>("Enter a Character:")
但是,为了使后者工作,你需要为字符实现FromStr,因为(遗憾的是)生锈似乎没有默认情况下这样做。像这样的东西,但是,我再也不确定这种生锈的语法。
use std::from_str::*;
impl FromStr for char {
fn from_str(s: &str) -> Option<Self> {
match len(s) {
x if x >= 1 => {
Option<char>.None
},
x if x == 0 => {
None,
},
}
return s[0];
}
}
答案 2 :(得分:0)
telotortium的输入读取功能的变体,在输入错误时不会失败。 loop { ... }
关键字比写while true { ... }
更受欢迎。在这种情况下,使用return
很好,因为函数提前返回。
fn int_from_input(prompt: &str) -> int {
println(prompt);
loop {
match from_str::<int>(io::stdin().read_line()) {
Some(x) => return x,
None => println("Oops, that was invalid input. Try again.")
};
}
}