文章目录
Rust是强类型的语言,不存在隐式类型转换。
不过幸好,Rust设计了强大的类型转换机制。
原生数值类型借助as
关键字进行类型转换
as关键字用于基础原生(primitive)类型的转换。
let i = 100i32;
// i32 -> u8
let b : u8 = i as u8;
// 超出u8范围的字面量常数,不能转换
// 编译报错:literal out of range for `u8`
// let b = 1000 as u8;
// u8 -> i32
let i : i32 = 10u8 as i32;
// char -> u8
let x1: u8 = 'x' as u8;
let x2: u8 = b'x';
assert_eq!(x1, x2);
// f32 -> i32
let y = 3.1f32 as i32;//3
// i32类型没有sqrt()方法
assert_eq!(2f32, (4i32 as f32).sqrt());
特别提醒:
i32类型中没有实现求算数平方根sqrt()
的方法。
如果需要对整数求平方根,再取整,可以这么做:
let x: i32 = 17;
let sqr: i32 = (x as f32).sqrt() as i32;
println!("{:?}", sqr);//4
小写英文字母转为数组下标
#[test]
fn test_char2index() {
let s = "abcd";
for c in s.chars() {
let idx = (c as u8 - b'a') as usize;
print!("{}", idx);//0123
}
}
字符串字面量转换为u8数组
let x: &[u8; 4] = b"abcd";
let y: [u8; 4] = b"abcd".to_owned();
字符串和数值类型的转换
//字符串转i32等数值类型
let x:i32 = "123".parse::<i32>().unwrap();
let x:u8 = "123".parse::<u8>().unwrap();
// 字符串转u8类型的切片
let x: &[u8] = "123".as_bytes();
// 数值类型转String
let s: String = 123i32.to_string();
let s: String = 123u8.to_string();
String和&str的转换
// 字符串字面量,即&str(字符串切片)类型转String
// 下面4种方式,本质都是掉clone()方法
// 一般使用第2/3种即可
let s1: String = "hello".to_string();
let s2: String = String::from("hello");
let s3: String = "Hello".to_owned();
let s4: String = "123".into();
// 反之,String转&str
let x: &str = s1.as_str();
let x: &str = &s1[..];
数组转列表
let list: Vec<i32> = [1,2,3,4].to_vec();
println!("list: {:?}", list);
Vec<u8>转String(String::from_utf8_lossy())
从&[u8]
类型中构造一个str
出来。
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> { ... }
from_utf8_lossy()
能够处理输入的u8
序列中包含非法utf8字符
的情况:
- 如果转换过程中遇到非法的序列(不能转成合法的
utf8字符
),在结果中用U+FFFD
(�字符)替代。此时,返回结果是一个具有所有权的str
类型。 - 如果转换一切顺利,返回的就是对原
u8
序列(构成的字符)的借用。
因此from_utf8_lossy()
的返回结果是一个Cow<str>
(Clone-On-Write
)枚举类型。
// 转换成功
let list = vec![b'o', b'k', b':', b'?', 0x44];
let str1 = String::from_utf8_lossy(&list);
println!("str1={:?}", str1.into_owned());//str1="ok:?D"
// 部分字符被�替代
let str2 = String::from_utf8_lossy(b"fail:\xF0\x90\x80").into_owned();
println!("str2={:?}", str2);//str2="fail:�"
Vec<u8>转String(String::from_utf8())
从Vec<u8>
类型中构造一个String
出来。
pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> { ... }
- 若能转换成合法的
utf8字符
序列,返回String
; - 若不能,返回
FromUtf8Error
;
即是说,转换结果是一个枚举类型:Result<String, FromUtf8Error>
。
use std::string::FromUtf8Error;
let list = vec![b'a', b'b', 0x3f, 0x44];
let str3: Result<String, FromUtf8Error> = String::from_utf8(list);
// 转换成功,通过unwrap()拿到Result中的合法值
println!("str3={:?}", str3.unwrap());//str3="ab?D"
// 转换失败
let str4: Result<String, FromUtf8Error> = String::from_utf8(vec![b'\xF0', b'\x90', b'\x80']);
println!("str4 is error: {:?}", str4.is_err());//str4 is error: true
字符数组/列表合并为一个String
let s = ['a','b','c','d'].iter().collect::<String>();
println!("{s}");//abcd
let s = (vec!['a','b','c','d']).iter().collect::<String>();
println!("{s}");//abcd
字符串数组/列表合并(join/concat)为一个String
let s = ["ab","cd"].concat();
println!("{s}");//abcd
let s = (vec!["ab","cd"]).concat();
println!("{s}");//abcd
let s = ["ab","cd"].join("-");
println!("{s}");//ab-cd
let s = (vec!["ab","cd"]).join("-");
println!("{s}");//ab-cd
trait From< T > 和Into< T >
这两个trait在标准库中的定义为:
// 实现此trait的类型X,能够通过调用X::from(t)从T类型的t得到一个X类型的对象
pub trait From<T>: Sized {
#[must_use]
fn from(_: T) -> Self;
}
// 实现此trait的对象能够将自身转换为T类型,通过调用自身的into()方法
pub trait Into<T>: Sized {
#[must_use]
fn into(self) -> T;
}
一般来说,我们应该尽量优先选择实现 From<T>
而不是 Into<T>
,因为当你为 U
实现 From<T>
,这也意味着你同时为 T
隐式实现了 Into<U>
。
//From<T> trait 和 Into<T> trait
struct Point {
x: i32,
y: i32,
}
impl Point {
fn new(x: i32, y: i32) -> Self {
Self{
x,y
}
}
}
impl From<Point> for String {
fn from(p: Point) -> Self {
format!("{},{}", p.x, p.y)
}
}
let point1 = Point::new(20,30);
let point2 = Point::new(20,30);
let point_str1: String = String::from(point1);
let point_str2: String = point2.into();
println!("{}",point_str1);//20,30
println!("{}",point_str2);//20,30
当转换不能100%确保成功的话,应该使用TryFrom<T>
和TryInto<T>
,运行转换失败时返回一个错误类型。
AsRef 和 std::ops::Deref
pub trait AsRef<T: ?Sized> {
/// Performs the conversion.
fn as_ref(&self) -> &T;
}
pub trait Deref {
/// The resulting type after dereferencing.
type Target: ?Sized;
/// Dereferences the value.
#[must_use]
fn deref(&self) -> &Self::Target;
}