Rust 使用 trait 解决类型之间的转换问题。最一般的转换会用到 From
和 into
两个 trait。
From 和 Into
From
trait 允许一种类型定义 “怎么根据另一种类型生成自己”。str
转 String
:
let my_str = "hello";
let my_string = String::from(my_str);
Into
trait 就是把 From
trait 倒过来而已。也就是说,如果你为你的类型实现了 From
,那么同时你也就免费获得了 Into
。
使用 Into
trait 通常要求指明要转换到的类型,因为编译器大多数时候不能推断它。
自定义转换规则:
use std::convert::From;
#[derive(Debug)]
struct Number {
value: i32,
}
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
fn main() {
let num = Number::from(30);
println!("My number is {:?}", num);
let int = 5;
let num: Number = int.into();
println!("My number is {:?}", num);
}
TryFrom 和 TryInto
TryFrom
和 TryInto
trait 用于易出错的转换,所以其返回值是 Result
型。
use std::convert::TryFrom;
use std::convert::TryInto;
#[derive(Debug, PartialEq)]
struct EvenNumber(i32);
impl TryFrom<i32> for EvenNumber {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value % 2 == 0 {
Ok(EvenNumber(value))
} else {
Err(())
}
}
}
fn main() {
// TryFrom
assert_eq!(EvenNumber::try_from(8), Ok(EvenNumber(8)));
assert_eq!(EvenNumber::try_from(5), Err(()));
// TryInto
assert_eq!(8.try_into(), Ok(EvenNumber(8)));
let result: Result<EvenNumber, ()> = 5i32.try_into();
assert_eq!(result, Err(()));
}
ToString 和 FromStr
把任何类型转化成 String
,只需要实现那个类型的 ToString
trait。但是建议实现 fmt::Display
trait,它会自动提供 ToString
,并且还可以用来打印类型。
use std::string::ToString;
struct Circle {
radius: i32
}
impl ToString for Circle {
fn to_string(&self) -> String {
format!("Circle of radius {:?}", self.radius)
}
}
fn main() {
let circle = Circle {: 6 };
println!("{}", circle.to_string());
}
解析字符串
字符串转数字,标准手段是使用 parse
函数。需要提供转换到的类型,或者使用 turbo fish 语法实现。
只要对目标类型实现了FromStr
trait,就可以用 parse
把字符串转为目标类型。
fn main() {
let parsed: i32 = "5".parse().unwrap();
let turbo_parsed = "10".parse::<i32>().unwrap();
let sum = parsed + turbo_parsed;
println!{"Sum: {:?}", sum};
}
自定义实现:
fn main() {
use std::str::FromStr;
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl FromStr for Point {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let x_fromstr = s.parse::<i32>().unwrap();
Ok(Point {
x: x_fromstr,
y: x_fromstr,
})
}
}
let p: Point = "1".parse().unwrap();
// 或者使用 from_str
// let p = Point::from_str("1");
println!("{:?}", p);
}