rust学习笔记之小练习:类型转换
类型转换
as 运算符
fn average(values: &[f64]) -> f64 {
let total = values.iter().sum::<f64>();
total / values.len() as f64
}
fn main() {
let values = [3.5, 0.3, 13.0, 11.7];
println!("{}", average(&values)); // 7.125
assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
}
From 和 Into trait
#[derive(Debug)]
struct Person {
name: String,
age: usize,
}
// 实现 Default trait
impl Default for Person {
fn default() -> Person {
Person {
name: String::from("John"),
age: 30,
}
}
}
// 实现 From<&str> trait
impl From<&str> for Person {
fn from(s: &str) -> Person {
if s.len()>0 {
if let Some((name,age))=s.split_once(','){
if ! name.is_empty(){
if let Ok(age)= age.parse::<usize>(){
return Self {
name:name.to_string(),
age
};
}
}
}
}
Self::default()
}
}
fn main() {
// 使用 `from` 函数
let p1 = Person::from("Mark,20");
assert_eq!(p1.name, "Mark");
assert_eq!(p1.age, 20);
// 由于 From 被 Person 实现了,我们应该可以使用 Into
let p2: Person = "Gerald,70".into();
assert_eq!(p2.name, "Gerald");
assert_eq!(p2.age, 70);
let dp = Person::default();
assert_eq!(dp.name, "John");
assert_eq!(dp.age, 30);
let vec = vec!["","Mark,twenty","Mark","Mark,",",1",",",",one","Mike,32,","Mike,32,man"];
for key in vec{
let p = Person::from(key);
assert_eq!(dp.name, "John");
assert_eq!(dp.age, 30);
}
}
TryFrom 和 TryInto trait
TryFrom 是一个简单和安全的的转换,在某些情况下会以可控方式失败。基本上与 From trait相同,主要的区别是这个返回一个 Result 类型而不是目标类型。
use std::convert::{TryFrom, TryInto};
#[derive(Debug, PartialEq)]
struct Color {
red: u8,
green: u8,
blue: u8,
}
// 这个错误类型用于 `TryFrom` 转换。
#[derive(Debug, PartialEq)]
enum IntoColorError {
BadLen,// 不正确的切片长度
IntConversion,// 整数转换错误
}
// 元组实现
impl TryFrom<(i16, i16, i16)> for Color {
type Error = IntoColorError;
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
match tuple{
(r @ 0..=255 , g @ 0..=255, b @ 0..=255)=>{
Ok(Color{red:r as u8,green:g as u8,blue:b as u8})
},
_=>{
Err(IntoColorError::IntConversion)
}
}
}
}
// 数组实现
impl TryFrom<[i16; 3]> for Color {
type Error = IntoColorError;
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
match arr{
[r @ 0..=255 , g @ 0..=255, b @ 0..=255]=>{
Ok(Color{red:r as u8,green:g as u8,blue:b as u8})
},
_=>{
Err(IntoColorError::IntConversion)
}
}
}
}
// 切片实现
impl TryFrom<&[i16]> for Color {
type Error = IntoColorError;
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
if slice.len()==3 {
match *slice{
[r @ 0..=255 , g @ 0..=255, b @ 0..=255]=>{
Ok(Color{red:r as u8,green:g as u8,blue:b as u8})
},
_=>{
Err(IntoColorError::IntConversion)
}
}
}else{
Err(IntoColorError::BadLen)
}
}
}
fn main() {
// 使用 `try_from` 函数
let c1 = Color::try_from((183, 65, 14));
println!("{:?}", c1);
// 由于 TryFrom 被实现于 Color,我们可以使用 TryInto
let c2: Result<Color, _> = [183, 65, 14].try_into();
println!("{:?}", c2);
let v = vec![183, 65, 14];
// 对于切片我们可以使用 `try_from` 函数
let c3 = Color::try_from(&v[..]);
println!("{:?}", c3);
// 或者用括号包含切片并使用 TryInto
let c4: Result<Color, _> = (&v[..]).try_into();
println!("{:?}", c4);
assert_eq!(Color::try_from((256, 1000, 10000)),Err(IntoColorError::IntConversion));
assert_eq!(Color::try_from((-1, -10, -256)),Err(IntoColorError::IntConversion));
assert_eq!(Color::try_from((-1, 255, 255)),Err(IntoColorError::IntConversion));
let c: Result<Color, _> = (183, 65, 14).try_into();
assert!(c.is_ok());
assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});
let c: Result<Color, _> = [1000, 10000, 256].try_into();
assert_eq!(c, Err(IntoColorError::IntConversion));
let c: Result<Color, _> = [-10, -256, -1].try_into();
assert_eq!(c, Err(IntoColorError::IntConversion));
let c: Result<Color, _> = [-1, 255, 255].try_into();
assert_eq!(c, Err(IntoColorError::IntConversion));
let c: Result<Color, _> = [183, 65, 14].try_into();
assert!(c.is_ok());
assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});
let arr = [10000, 256, 1000];
assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));
let arr = [-256, -1, -10];
assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));
let arr = [-1, 255, 255];
assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));
let v = vec![183, 65, 14];
let c: Result<Color, _> = Color::try_from(&v[..]);
assert!(c.is_ok());
assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});
let v = vec![0, 0, 0, 0];
assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
let v = vec![0, 0];
assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
}
FromStr trait
实现了 FromStr 的类型,可以用字符串使用 parse 方法来生成一个实现者类型的对象。parse 方法返回 Result<T,E> 类型。
use std::num::ParseIntError;
use std::str::FromStr;
#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: usize,
}
// 错误类型于 `FromStr` 实现。
#[derive(Debug, PartialEq)]
enum ParsePersonError {
Empty,// 空的输入字符串
BadLen,// 不正确的字段数
NoName,// 空的 name 字段
ParseInt(ParseIntError),// 包装来自 parse::<usize>() 的错误
}
// 实现 FromStr trait
impl FromStr for Person {
type Err = ParsePersonError;
fn from_str(s: &str) -> Result<Person, Self::Err> {
if s.len()>0 {
let vec:Vec<&str>=s.split(',').collect();
if let [name,age]=&vec[..]{
if ! name.is_empty(){
return match age.parse::<usize>(){
Ok(age)=> Ok(Self {
name:name.to_string(),
age
}),
Err(error)=>Err(ParsePersonError::ParseInt(error)),
};
}else{
return Err(ParsePersonError::NoName);
}
}else{
return Err(ParsePersonError::BadLen);
}
}
Err(ParsePersonError::Empty)
}
}
fn main() {
let p = "Mark,20".parse::<Person>().unwrap();
println!("{:?}", p);
let p = "John,32".parse::<Person>();
assert!(p.is_ok());
let p = p.unwrap();
assert_eq!(p.name, "John");
assert_eq!(p.age, 32);
assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));
assert!(matches!("John,".parse::<Person>(),Err(ParsePersonError::ParseInt(_))));
assert!(matches!("John,twenty".parse::<Person>(),Err(ParsePersonError::ParseInt(_))));
assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));
assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));
assert!(matches!(",".parse::<Person>(),Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))));
assert!(matches!(",one".parse::<Person>(),Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))));
assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));
assert_eq!("John,32,man".parse::<Person>(),Err(ParsePersonError::BadLen));
}
AsRef 和 AsMut trait
通过 AsRef trait 实现从一种类型的不可变引用转换为另一种类型的不可变引用。通过 AsMut trait 实现从一种类型的可变引用转换为另一种类型的可变引用。通常用于类型转换。
fn byte_counter<T: AsRef<str>>(arg: T) -> usize {
arg.as_ref().as_bytes().len()
}
fn char_counter<T: AsRef<str>>(arg: T) -> usize {
arg.as_ref().chars().count()
}
fn num_sq<T: AsMut<u32>>(arg: &mut T) {
let p: &mut u32=arg.as_mut();
*p = *p * *p;
}
fn main() {
let s = "Café au lait";
assert_ne!(char_counter(s), byte_counter(s));
let s = "Cafe au lait";
assert_eq!(char_counter(s), byte_counter(s));
let s = String::from("Café au lait");
assert_ne!(char_counter(s.clone()), byte_counter(s));
let s = String::from("Cafe au lait");
assert_eq!(char_counter(s.clone()), byte_counter(s));
let mut num: Box<u32> = Box::new(3);
num_sq(&mut num);
assert_eq!(*num, 9);
}
浙公网安备 33010602011771号