Rust类型转换

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字符的情况:

  1. 如果转换过程中遇到非法的序列(不能转成合法的utf8字符),在结果中用U+FFFD(�字符)替代。此时,返回结果是一个具有所有权的str类型。
  2. 如果转换一切顺利,返回的就是对原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> { ... }
  1. 若能转换成合法的utf8字符序列,返回String
  2. 若不能,返回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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值