当前位置: 首页 > news >正文

玩转Rust高级应用. ToOwned trait 提供的是一种更“泛化”的Clone 的功能,Clone一般是从T类型变量创造一个新的T类型变量

标准库简介

除了前面介绍过的容器、迭代器之外,标准库还提供了一系列有用的类型、函数、 trait 等。本章挑选其中比较常见的一部分简单介绍。

类型转换

Rust 给我们提供了一个关键字as 用于基本类型的转换。但是除了基本类型之外,还有 更多的自定义类型,它们之间也经常需要做类型转换。为此, Rust 标准库给我们提供了一系 列 的trait 来辅助抽象。

AsRef/AsMut

AsRef 这个trait 代表的意思是,这个类型可以通过调用as_ref方法,得到另外一个 类型的共享引用。它的定义如下:

pub trait AsRef < T: ?Sized > {fn as_ref( & self) - >&T;
}

同 理 ,ASMut 有 一 个 as_mut方法,可以得到另外一个类型的可读写引用:

pub trait ASMut < T: ?Sized > {fn as_mut( & mut self) - >&mut T;
}

比如说,标准库里面的String类型,就针对好几个类型参数实现了AsRef trait:

impl AsRef < str >
for String impl AsRef < [u8] >
for String impl AsRef < 0sStr >
for String impl AsRef < Path >
for String

AsRef 这样的trait 很适合用在泛型代码中,为一系列类型做统一抽象。比如,我们可 以写一个泛型函数,它接受各种类型,只要可以被转换为&[u8] 即可:

fn iter_bytes < T: AsRef < [u8] >> (arg: T) {for i in arg.as_ref() {println ! ("{}", i);}
}
fn main() {let s: String = String: :from("this is a string");let v: Vec < u8 >= vec ! [1, 2, 3];let c: &str = "hello";
}

相当于函数重载。只不过基于泛型实现的重载,一定需要重载的参数类型满足某种共同的约束 iter_bytes(s);

{iter_bytes(V);iter_bytes(c);
}

Borrow/BorrowMut

Borrow 这个trait 设计得与AsRef 非常像。它是这样定义的:

pub trait Borrow < Borrowed: ?Sized > {fn borrow( & self) - >&Borrowed;
}

可以说,除了名字之外,它和AsRef 长得一模一样。但它们的设计意图不同。比如, 针对String 类型,它只实现了一个Borrow:

impl Borrow<str>for String

这是因为这个trait 一般被用于实现某些重要的数据结构,比如HashMap:

impl HashMap {pub fn get < Q: ?Sized > ( & self, k: &Q) - >Option < &V > where K: Borrow < Q > ,Q: Hash + Eq {}
}

和 BTreeMap:

impl BTreeMap {pub fn get < Q: ?Sized > ( & self, key: &Q) - >Option < &V > where K: Borrow < Q > ,Q: Ord {}
}

所以,它要求borrow() 方法返回的类型,必须和原来的类型具备同样的hash值,以及排序。这是一个约定,如果实现Borrow trait的时候违反了这个约定,那么把这个类型放 到 HashMap 或者BTreeMap 里面的时候就可能出现问题。


From/Into

AsRef/Borrow做的类型转换都是从一种引用&T 到另一种引用&U的转换。而From/Into 做的则是从任意类型T 到 U 的类型转换:

pub trait From < T > {fn from(T) - >Self;
}
pub trait Into < T > {fn into(self) - >T;
}

显然,From 和 Into 是互逆的一组转换。如果T 实现了From, 那 么U理应实现 Into 。 因此,标准库里面提供了这样一个实现:

impl < T,
U > Into < U >
for T where U: From < T > {fn into(self) - >U {U: :from(self)}
}

用自然语言描述,意思就是:如果存在U:From, 则实现T:Into

正是因为标准库中已经有了这样一个默认实现,我们在需要给两个类型实现类型转换的 trait的时候,写一个From 就够了,Into 不需要自己手写。

比如,标准库里面已经给我们提供了这样的转换:

impl<a>From<&a str>for String

这意味着&str 类型可以转换为String 类型。我们有两种调用方式: 一种是通过 String::from(&str) 来使用,一种是通过&str::into() 来使用。它们的意思一样:

fn main() {let s: &'static str ="hello";let str1:String =s.into();let str2:String =String::from(s);
}

另外,由于这几个trait很常用,因此Rust已经将它们加入到prelude中。在使用的时 候我们不需要写use std::convert::From;这样的语句了,包括AsRef、ASMut、Into、From、ToOwned 等。具体可以参见libstd/prelude/v1.rs源代码的内容。

标准库中还有一组对应的TryFrom/TryInto 两个trait, 它们是为了处理那种类型转 换过程中可能发生转换错误的情况。因此,它们的方法的返回类型是Result类型。


ToOwned

ToOwned trait 提供的是一种更“泛化”的Clone 的功能。Clone 一般是从&T 类型变 量创造一个新的T 类型变量,而ToOwned 一般是从一个&T 类型变量创造一个新的U类型 变 量 。

在标准库中,ToOwned 有一个默认实现,即调用clone 方法:

impl < T > ToOwned
for T where T: Clone {type Owned = T;fn to_owned( & self) - >T {self.clone()fn clone_into( & self, target: &mut T) {target.clone_from(self);}}
}

但是,它还对一些特殊类型实现了这个trait 。比如:

impl < T: Clone > ToOwned
for [T] {type Owned = Vec < T > ;
}
impl ToOwned
for str {type Owned = String;
}

而且,很有用的类型Cow 也是基于ToOwned 实现的:

pub enum Cow < 'a,B>
where
B:'a + ToOwned + ?Sized,
{Borrowed( & 'a B),Owned(<B as ToOwned>::Owned),
}
// ToString trait提供了其他类型转换为String 类型的能力。
pub trait ToString{fn to_string(&self)->String;
}

一般情况下,我们不需要自己为自定义类型实现ToString trait。因为标准库中已经提供 了 一 个 默 认 实 现 :

impl < T: fmt: :Display + ?Sized > ToString
for T {# [inline]
default fn to_string( & self) - >String {use core: :fmt: :Write;let mut buf = String: :new();buf.write_fmt(format_args ! ("{}", self)).expect("a Display implementation return an error     unexpectedly");buf.shrink_to_fit();buf}
}

这意味着,任何一个实现了Display trait 的类型,都自动实现了ToString trait。而 Display trait 是可以自动derive 的,我们只需要为类型添加一个attribute 即可。

FromStr则提供了从字符串切片&str 向其他类型转换的能力。

pub trait FromStr {type Err;fn from_str(s: &str) - >Result < Self,Self: :Err > ;
}

因为这个转换过程可能出错,所以from_str 方法的返回类型被设计为Result。正是因为有了这个trait, 所 以str类型才有了一个成员方法parse:

pub fn parse<F:FromStr>(&self)->Result<F,F::Err>{}

所以我们可以写下面这样非常清晰直白的代码:

let four ="4".parse::<u32>();
assert_eq!(Ok(4),four);
http://www.dtcms.com/a/585742.html

相关文章:

  • 11.8 脚本网页 推箱子
  • 网站建设要钱么深圳一百讯网站建设
  • [Java算法] 双指针(1)
  • 江苏省建设厅网站官网湖南做网站最厉害的公司
  • 杭州家具网站建设方案郑州app开发价格
  • gdb调试命令和GDB 到 LLDB 命令映射
  • 【CUDA笔记】02 CUDA GPU 架构与一般的程序优化思路(上)
  • 198种组合算法+优化XGBoost+SHAP分析+新数据预测!机器学习可解释分析,强烈安利,粉丝必备!
  • 东莞做网站要多少钱安顺建设局网站官网
  • 在线做h5 的网站网站服务器怎么查询
  • Vue 项目实战《尚医通》,展示已有医院的数据并分页展示,笔记11
  • Modbus RTU 转 Modbus TCP:借助数据采集提升三菱PLC冷库温度反馈实时性案例
  • DeepSeek-OCR实战(01):基础运行环境搭建-Ubuntu
  • SQLite 索引:优化数据库查询的关键
  • 可拖拽网站三星官网商城
  • MySQL 8.x 的 my.ini配置设置
  • 周志华《机器学习导论》第 15 章 规则学习(符号主义学习)
  • 使用pycharm自带debug模式运行flask时报错
  • 福州做网站需要多少钱懒设计app
  • Dify 安全架构设计
  • 网站推广国外网站建设素材库
  • Rust 练习册 :Pythagorean Triplet与数学算法
  • 构建一个短链接生成器服务(FastAPI + SQLite)
  • 基于SpringBoot智慧社区系统/乡村振兴系统/大数据与人工智能平台
  • 做网站的公司跑了wordpress 首页显示产品
  • BLDCPMSM电机控制器硬件设计工程(八)72V 10kW电机控制器原理图工程及库文件
  • 西宁的网站建设公司怎样建立网站的快捷方式
  • MATLAB基于IOWGA算子的最优组合预测模型及应用
  • HarmonyOS Web组件深度解析:构建高性能JavaScript交互的实践与创新
  • 华为OD机试双机位A卷 - 竖直四子棋 (JAVA Python C++ JS GO)