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 生成:

  1. let string = "hello".to_string();
  2. let other_string = String::from("hello");
  3. assert_eq!(string, other_string);

From

对于一个类型为 U: Into<T> 的对象 fooInto 提供了一个函数:.into(self) -> T,调用 foo.into() 会消耗自己(转移资源所有权),生成类型为 T 的另一个新对象 bar

2、PartialEq & Eq

等于比较 == ,两者都需要满足的条件有:

  • 对称性(Symmetry): a == b 可推出 b== a
  • 传递性(Transitivity): a == bb == c 可推出 a == c

而 Eq 需要额外满足的条件有:

  • 反身性: a == a

PartialEq 可使用 #[derive] 来交由编译器实现,这样一个 struct 在进行相等比较时,会对其中每一个字段进行比较,如果遇到枚举,还会对枚举所拥有的数据进行比较。你也可以自己实现自己的 PartialEq 方法,例子如下:

  1. #[derive(std::fmt::Debug)]
  2. struct Book {
  3. isbn: i32,
  4. name: String,
  5. }
  6. impl PartialEq for Book {
  7. fn eq(&self, other: &Self) -> bool {
  8. self.isbn == other.isbn
  9. }
  10. }
  11. fn main() {
  12. let a = Book {
  13. isbn: 112,
  14. name: String::from("science"),
  15. };
  16. let b = Book {
  17. isbn: 112,
  18. name: String::from("science"),
  19. };
  20. println!("{:?}", a == b); // true
  21. }

实现 Eq 的前提是已经实现了 PartialEq,对于上面的例子,可以使用 #[derive(Debug)] 或者 impl Eq for Book{} 即可。

如果你实现了PartialEq , 那么请你也尽可能一并实现 Eq,除非不允许(不能)! 对于浮点类型,Rust 只实现了 PartialEq 而不是 Eq,原因就是 NaN != NaN

3、Hash

散列值与相等的概念密切相关,因此如果实现自己的PartialEq Trait,还应该实现Hash Trait

一个原则: if x == y then hash(x) == hash(y)

将对FileInfo求哈希值委托给其成员 path:

  1. impl Hash for FileInfo {
  2. fn hash<H: Hasher>(&self, hasher: &mut H) {
  3. self.path.hash(hasher); //注意此处,hash a FileInfo就是hash其path。
  4. }
  5. }

这种委托技术适用于所有类型,因为标准库中的所有基本类型都实现了PartialEqHash

4、Ord & ParticalOrd

使用运算符<<=>=>可以计算值的相对顺序,为此必须为自定义类型实现PartialOrd

类似于 Eq,Ord 指的是 Total Order,需要满足以下三个性质:

  • 反对称性(Antisymmetry):a <= ba >= b 可推出 a == b
  • 传递性(Transitivity):a <= bb <= c 可推出 a <= c
  • 连通性(Connexity):a <= ba >= b

而 PartialOrd 无需满足连通性,只满足反对称性和传递性即可。

  • 反对称性:a < b 则有 !(a > b),反之亦然
  • 传递性:a < bb < c 可推出 a < c==> 同理

Ord & PartialOrd 均可通过 #[derive] 交由编译器自动实现,当使用 #[derive] 实现后,将会基于 struct 的字段声明以字典序进行比较,遇到枚举中的数据也会以此类推。

依赖要求:

  • PartialOrd 要求你的类型实现 PartialEq
  • Ord 要求你的类型实现 PartialOrd 和 Eq(因此 PartialEq 也需要被实现)

示例:

  1. impl PartialOrd for FileInfo {
  2. fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  3. self.path.partial_cmp(&other.path)
  4. }
  5. }

其中 Ordering 是一个简单的枚举类型,有 3 个可能的值:

  1. pub enum Ordering {
  2. Less,
  3. Equal,
  4. Greater,
  5. }

partial_cmp 这个方法返回值类型是个 Option,而非直接是一个Ordering值类型。 (这仍然与浮点数类型有关, 因为NaN不是一个可以表示的数值, 诸如:3.0 < NaN这样的表达式毫无意义!对于这种情况,partial_cmp就会返回None 因此浮点数是Rust标准库中发生此结果的唯一特例。)

  1. impl Ord for FileInfo {
  2. fn cmp(&self, other: &Self) -> Ordering {
  3. self.path.cmp(&other.path) //将排序委托给其成员path。
  4. }
  5. }

5、AsRef 和 AsMut

http://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/borrow-and-asref.html
std::convert 下面,还有另外两个 Trait,AsRef/AsMut,它们功能是配合泛型,在执行引用操作的时候,进行自动类型转换。这能够使一些场景的代码实现得清晰漂亮,大家方便开发。

AsRef

AsRef 提供了一个方法 .as_ref()
对于一个类型为 T 的对象 foo,如果 T 实现了 AsRef<U>,那么,foo 可执行 .as_ref() 操作,即 foo.as_ref()。操作的结果,我们得到了一个类型为 &U 的新引用。
注:

  1. Into<T> 不同的是,AsRef<T> 只是类型转换,foo 对象本身没有被消耗;
  2. T: AsRef<U> 中的 T,可以接受 资源拥有者(owned)类型,共享引用(shared referrence)类型 ,可变引用(mutable referrence)类型。

示例:

  1. fn is_hello<T: AsRef<str>>(s: T) {
  2. assert_eq!("hello", s.as_ref());
  3. }
  4. let s = "hello";
  5. is_hello(s);
  6. let s = "hello".to_string();
  7. 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 的超集。

  1. use std::borrow::Borrow;
  2. fn check<T: Borrow<str>>(s: T) {
  3. assert_eq!("Hello", s.borrow());
  4. }
  5. let s = "Hello".to_string();
  6. check(s);
  7. let s = "Hello";
  8. 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;
ToOwnedClone 的普适版本。它提供了 .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

参考