FromStr là một trait để khởi tạo instance từ string trong Rust, nó tương đương abstract class nếu bạn có background OOP.
pub trait FromStr {
type Err;
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
Thường phương thức from_str
của FromStr
thường được ngầm định
sử dụng thông qua phương thức parse
của str. Ví dụ:
// Thay vì
let one = u32::from_str("1");
// thì sử dụng phương thức parse
let one: u32 = "1".parse().unwrap();
assert_eq!(1, one);
// parse() sử dụng turbofish ::<>
let two = "2".parse::<u32>();
assert_eq!(Ok(2), two);
let nope = "j".parse::<u32>();
assert!(nope.is_err());
parse
là một phương thức general nên thường được sử dụng với kiểu dữ liệu
như trên hoặc sử dụng turbofish ::<>
để thuật toán inference có thể hiểu
để parse thành đúng kiểu bạn cần.
Parse str to Struct
Bạn có 1 struct và muốn parse 1 str thành struct đó, bạn sẽ cần impl trait FromStr
use std::str::FromStr;
use std::num::ParseIntError;
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32
}
impl FromStr for Point {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
.split(',')
.collect();
let x_fromstr = coords[0].parse::<i32>()?;
let y_fromstr = coords[1].parse::<i32>()?;
Ok(Point { x: x_fromstr, y: y_fromstr })
}
}
// Có nhiều cách
let p: Point = "(1,2)".parse();
let p = "(1,2)".parse::<Point>();
let p = Point::from_str("(1,2)");
assert_eq!(p.unwrap(), Point{ x: 1, y: 2} )
Parse str to Enum
Một điều mình thấy để code dễ đọc, dễ maintain hơn là chúng ta nên tránh sử dụng stringly-typed apis. Ví dụ như:
fn print(color: &str, text: &str) { ... }
print("Foobar", "blue");
Thay vì đó mà hãy sử dụng enum:
enum Color { Red, Green, CornflowerBlue }
fn print(color: Color, text: &str) { ... }
print(Green, "duyet");
Cũng nên hạn chế sử dụng quá nhiều Boolean, thực tế Boolean cũng chỉ là
enum bool { true, false }
Thay vào đó hãy tự định nghĩa enum cho các ngữ cảnh khác nhau để code dễ đọc hơn:
enum EnvVars { Clear, Inherit }
enum DisplayStyle { Color, Monochrome }
Chúng ta implement std::str::FromStr trait như sau:
use std::str::FromStr;
#[derive(Debug, PartialEq)]
enum Color {
Red,
Green,
Blue
}
impl FromStr for Color {
type Err = ();
fn from_str(input: &str) -> Result<Color, Self::Err> {
match input {
"red" => Ok(Color::Red),
"green" => Ok(Color::Green),
"blue" => Ok(Color::Blue),
_ => Err(()),
}
}
}
let c: Color = "red".parse().unwrap();
assert_eq!(c, Color::Red);