1、Into 和 From
Into
std::convert 下面,有两个 Trait,Into/From。它们的作用是配合泛型,进行一些设计上的归一化处理。
它们的基本形式为: From<T> 和 Into<T>。
对于类型为 U 的对象 foo,如果它实现了 From<T>,那么,可以通过 let foo = U::from(bar) 来生成自己。这里,bar 是类型为 T 的对象。
示例, String 实现了 From<&str>,所以 String 可以从 &str 生成:
let string = "hello".to_string();let other_string = String::from("hello");assert_eq!(string, other_string);
From
对于一个类型为 U: Into<T> 的对象 foo,Into 提供了一个函数:.into(self) -> T,调用 foo.into() 会消耗自己(转移资源所有权),生成类型为 T 的另一个新对象 bar。
2、PartialEq & Eq
等于比较 == ,两者都需要满足的条件有:
- 对称性(Symmetry):
a == b可推出 b== a - 传递性(Transitivity):
a == b且b == c可推出a == c
而 Eq 需要额外满足的条件有:
- 反身性:
a == a
PartialEq 可使用 #[derive] 来交由编译器实现,这样一个 struct 在进行相等比较时,会对其中每一个字段进行比较,如果遇到枚举,还会对枚举所拥有的数据进行比较。你也可以自己实现自己的 PartialEq 方法,例子如下:
#[derive(std::fmt::Debug)]struct Book {isbn: i32,name: String,}impl PartialEq for Book {fn eq(&self, other: &Self) -> bool {self.isbn == other.isbn}}fn main() {let a = Book {isbn: 112,name: String::from("science"),};let b = Book {isbn: 112,name: String::from("science"),};println!("{:?}", a == b); // true}
实现 Eq 的前提是已经实现了 PartialEq,对于上面的例子,可以使用 #[derive(Debug)] 或者 impl Eq for Book{} 即可。
如果你实现了PartialEq , 那么请你也尽可能一并实现 Eq,除非不允许(不能)! 对于浮点类型,Rust 只实现了 PartialEq 而不是 Eq,原因就是
NaN != NaN。
3、Hash
散列值与相等的概念密切相关,因此如果实现自己的PartialEq Trait,还应该实现Hash Trait 。
一个原则: if
x == ythenhash(x) == hash(y)
将对FileInfo求哈希值委托给其成员 path:
impl Hash for FileInfo {fn hash<H: Hasher>(&self, hasher: &mut H) {self.path.hash(hasher); //注意此处,hash a FileInfo就是hash其path。}}
这种委托技术适用于所有类型,因为标准库中的所有基本类型都实现了PartialEq 和 Hash。
4、Ord & ParticalOrd
使用运算符<、<=、>=和>可以计算值的相对顺序,为此必须为自定义类型实现PartialOrd。
类似于 Eq,Ord 指的是 Total Order,需要满足以下三个性质:
- 反对称性(Antisymmetry):
a <= b且a >= b可推出a == b - 传递性(Transitivity):
a <= b且b <= c可推出a <= c - 连通性(Connexity):
a <= b或a >= b
而 PartialOrd 无需满足连通性,只满足反对称性和传递性即可。
- 反对称性:
a < b则有!(a > b),反之亦然 - 传递性:
a < b且b < c可推出a < c,==和>同理
Ord & PartialOrd 均可通过 #[derive] 交由编译器自动实现,当使用 #[derive] 实现后,将会基于 struct 的字段声明以字典序进行比较,遇到枚举中的数据也会以此类推。
依赖要求:
- PartialOrd 要求你的类型实现 PartialEq
- Ord 要求你的类型实现 PartialOrd 和 Eq(因此 PartialEq 也需要被实现)
示例:
impl PartialOrd for FileInfo {fn partial_cmp(&self, other: &Self) -> Option<Ordering> {self.path.partial_cmp(&other.path)}}
其中 Ordering 是一个简单的枚举类型,有 3 个可能的值:
pub enum Ordering {Less,Equal,Greater,}
partial_cmp这个方法返回值类型是个 Option,而非直接是一个Ordering值类型。 (这仍然与浮点数类型有关, 因为NaN不是一个可以表示的数值, 诸如:3.0 < NaN这样的表达式毫无意义!对于这种情况,partial_cmp就会返回None因此浮点数是Rust标准库中发生此结果的唯一特例。)
impl Ord for FileInfo {fn cmp(&self, other: &Self) -> Ordering {self.path.cmp(&other.path) //将排序委托给其成员path。}}
5、AsRef 和 AsMut
http://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/borrow-and-asref.htmlstd::convert 下面,还有另外两个 Trait,AsRef/AsMut,它们功能是配合泛型,在执行引用操作的时候,进行自动类型转换。这能够使一些场景的代码实现得清晰漂亮,大家方便开发。
AsRef
AsRef 提供了一个方法 .as_ref()。
对于一个类型为 T 的对象 foo,如果 T 实现了 AsRef<U>,那么,foo 可执行 .as_ref() 操作,即 foo.as_ref()。操作的结果,我们得到了一个类型为 &U 的新引用。
注:
- 与
Into<T>不同的是,AsRef<T>只是类型转换,foo对象本身没有被消耗; T: AsRef<U>中的T,可以接受 资源拥有者(owned)类型,共享引用(shared referrence)类型 ,可变引用(mutable referrence)类型。
示例:
fn is_hello<T: AsRef<str>>(s: T) {assert_eq!("hello", s.as_ref());}let s = "hello";is_hello(s);let s = "hello".to_string();is_hello(s);
因为
String和&str都实现了AsRef<str>。
AsMut
AsMut<T> 提供了一个方法 .as_mut()。它是 AsRef<T> 的可变(mutable)引用版本。
对于一个类型为 T 的对象 foo,如果 T 实现了 AsMut<U>,那么,foo 可执行 .as_mut() 操作,即 foo.as_mut()。操作的结果,我们得到了一个类型为 &mut U 的可变(mutable)引用。
注:在转换的过程中,foo 会被可变(mutable)借用。
6、Borrow, BorrowMut, ToOwned
Borrow
use std::borrow::Borrow;Borrow 提供了一个方法 .borrow()。
对于一个类型为 T 的值 foo,如果 T 实现了 Borrow<U>,那么,foo 可执行 .borrow() 操作,即 foo.borrow()。操作的结果,我们得到了一个类型为 &U 的新引用。Borrow 可以认为是 AsRef 的严格版本,它对普适引用操作的前后类型之间附加了一些其它限制。Borrow 的前后类型之间要求必须有内部等价性。不具有这个等价性的两个类型之间,不能实现 Borrow。AsRef 更通用,更普遍,覆盖类型更多,是 Borrow 的超集。
use std::borrow::Borrow;fn check<T: Borrow<str>>(s: T) {assert_eq!("Hello", s.borrow());}let s = "Hello".to_string();check(s);let s = "Hello";check(s);
BorrowMut
use std::borrow::BorrowMut;BorrowMut<T> 提供了一个方法 .borrow_mut()。它是 Borrow<T> 的可变(mutable)引用版本。
对于一个类型为 T 的值 foo,如果 T 实现了 BorrowMut<U>,那么,foo 可执行 .borrow_mut() 操作,即 foo.borrow_mut()。操作的结果我们得到类型为 &mut U 的一个可变(mutable)引用。
注:在转换的过程中,foo 会被可变(mutable)借用。
ToOwned
use std::borrow::ToOwned;ToOwned 为 Clone 的普适版本。它提供了 .to_owned() 方法,用于类型转换。
有些实现了 Clone 的类型 T 可以从引用状态实例 &T 通过 .clone() 方法,生成具有所有权的 T 的实例。但是它只能由 &T 生成 T。而对于其它形式的引用,Clone 就无能为力了。
而 ToOwned trait 能够从任意引用类型实例,生成具有所有权的类型实例。
Index
Error
实现 Error trait,这样其他错误可以包裹这个错误类型。
Cow
Cow 是一个枚举类型,通过 use std::borrow::Cow; 引入。它的定义是 Clone-on-write,即写时克隆。本质上是一个智能指针。
https://wiki.jikexueyuan.com/project/rust-primer/intoborrow/cow.html
