在Rust中使用stdin数据实例化struct

isp*_*ava 3 closures rust

我对Rust非常非常新,并试图实现一些简单的东西来感受语言.现在,我绊倒了实现类似类的结构的最佳方法,该结构涉及将字符串转换为int.我正在使用全局命名空间的函数,我觉得我的红宝石大脑感觉不对.

这样做的乡村方式是什么?

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();
}
Run Code Online (Sandbox Code Playgroud)

这会编译并具有所需的行为,但我不知道该做什么 - 显然我不了解最佳实践或如何实现它们.

编辑:这是0.8

tel*_*ium 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();
}
Run Code Online (Sandbox Code Playgroud)

fmt!/format!

首先,Rust正在弃用fmt!宏,使用printf基于语法的语言format!,而使用类似于Python格式字符串的语法.新版本的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);
Run Code Online (Sandbox Code Playgroud)

初始化结构

对于类似的简单类型Person,在Rust中使用struct literal语法创建该类型的实例是惯用的:

let first_person = Person {
    name: ~"Ohai",
    age:  get_int_from_input("Please enter a number for age.")
};
Run Code Online (Sandbox Code Playgroud)

如果你想要一个构造函数,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表示在交换堆中分配一个字符串-换句话说,该堆malloc/ free在C,或new/ deleteC++中进行操作.但是,与C/C++不同,Rust强制要求交换堆上的值一次只能由一个变量拥有.因此,将a ~str作为函数参数意味着函数的调用者不能重用~str它传入的参数 - 它必须复制~str使用该.clone方法.

另一方面,&str是字符串中的切片,它只是对字符串中一系列字符的引用,因此在调用带&str参数的函数时,不需要分配新的字符串副本.

使用的原因&str,而不是~str用于prompt_messageget_int_from_input是该功能不需要守住过去的函数结束的消息.它只使用提示信息来打印它(并println采用a &str而不是a ~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`.
Run Code Online (Sandbox Code Playgroud)

Option<T>::expect

Option<T>::expect方法是您拥有的匹配语句的惯用快捷方式,x如果您收到Some(x)或未通过消息,您希望返回该方法None.

没有回来 return

在Rust中,它是惯用的(遵循像Haskell和OCaml这样的函数式语言的示例)来返回值而不显式编写return语句.实际上,函数的返回值是函数中最后一个表达式的结果,除非表达式后跟一个分号(在这种情况下它返回(),也就是unit,它本质上是一个空的占位符值 - ()也是什么由没有显式返回类型的函数返回,例如mainor print_info).

结论

无论如何,我不是Rust的伟大专家.如果您需要有关Rust的任何帮助,除了Stack Overflow之外,您还可以尝试irc.mozilla.org上的#rust IRC频道或Rust subreddit.

  • 重新'println(格式!(...))`vs`println!(...)`:前者必须分配一个`~str`然后打印它,但后者直接写入`stdout`,不需要不必要的`~str`缓冲区,所以使用`println!`宏也更高效. (2认同)