基础类型(Primitive Type)

Rust语言提供了若干基础类型。我们马上会逐一介绍。
基础类型与Rust语言紧密绑定在一起,在很多时候会展现出用户自定义类型无法具有的行为。

布尔类型:bool

布尔类型的名称为bool,包含两个值:。Rust通过两个关键词truefalse,分别表示这两个值。请看下面的代码示例:

  1. #[allow(unused)]
  2. fn main{
  3. let b: bool = true;
  4. // 在上面这行语句中,声明了一个bool类型的变量b,并将true值赋给变量b
  5. // 对于赋值符号右侧的true,可以从三个方面来理解:
  6. // 1. true是Rust语言的一个关键词
  7. // 2. true是一个字面量(literal),表示bool类型的真值
  8. // 3. true是一个字面量表达式(literal expression)
  9. // 对这个表达式求值,得到bool类型的真值
  10. let c = false;
  11. // 在上面的语句中,没有声明变量c的类型
  12. // 但是,这并不会导致编译错误
  13. // 因为,Rust编译器会通过类型推断(type inference)确定变量c的类型
  14. // 所谓类型推断,大概就是从变量声明和使用的上下文中推断出变量的类型
  15. }
  16. // 对 #[allow(unused)] 的说明:
  17. // 1. 这是一个关于函数main的属性声明(attribute declaration)
  18. // 表示允许在main的代码中出现未使用的变量
  19. // 2. 如果删除这个属性声明,那么,如果main函数中存在未使用的变量,
  20. // 则Rust编译器会报出警告(warning)
  21. // 3. 在上面的程序中,如果删除了这个属性声明,
  22. // 则编译器会报出警告:unused variable: `b`

布尔类型看起来像是一个枚举(enum)类型,因为它看起来确实只有两个变体(variant)。但是,Rust并没有把布尔类型实现为枚举类型。

内存排布(Memory Layout)

一个bool类型的值,在内存中的排布方式如下:

  • 占用一个字节
    • 也称bool类型的size等于1
    • 也称bool类型是一种定长类型(sized type);因为bool类型的所有值都具有相同的size。
  • 占用的这个字节必须是内存空间中具有编号/地址的一个字节
    • 也即:这个被占用的字节,不能分散在内存空间中具有地址的两个字节中
    • bool类型的这种排布要求,被描述为allignment等于1
  • true值表示为二进制串0x01false值表示为二进制串0x00 :::info 在后面,我们会看到allignment等于其他值的情况。
    Allignment的取值只能是一个正整数,且必须是2的整数次方,也即:1、2、4、8等值。
    举例而言,如果类型T的allignment为2,那么,该类型的值只能排布在内存中满足如下条件的位置:

  • 该位置的首字节的地址能被2整除

对值的排布位置进行这种限制的目的是什么呢?这个问题大概与计算机硬件系统的特点以及程序的运行效率有关系。时机成熟后,我们再来看这个问题。 :::

自动实现的特性(traits)

Rust为所有基础类型自动实现了5种特性(trait):SizedCloneCopySend、以及Sync。下面,我们简单介绍前三种特性。后面的两种特性,留到后面合适的地方再介绍。

Sized

如果类型T实现了Sized特性,则表明T是一种定长的数据类型,即:类型T的所有值在内存中占据相同的字节数,且这个字节数在编译时刻就能确定。编译器能够自动根据一个类型的定义,确定它是否是定长类型;如果是,则自动为该类型实现Sized特性。
bool类型的内存排布可知,bool类型是一种定长类型。因此,编译器自动为它实现了Sized特性。
Sized是一种标记型的特性(maker trait)。因为除了对类型做出标记外,Sized并不会在类型上添加什么其他成分。

Clone

如果类型T实现了Clone特性,则对T的任何一个值v,我们可以调用特定的方法生成值v的一个克隆c,即:vc在语义上是两个相同的值;但是,它们在内存中的排布是完全独立的(改变一个值,并不会导致另外一个值发生变化)。
下面给出了定义Clone特性的源代码:

  1. // 可以将Rust中的trait大概对应到Java中的interface:
  2. // 1. 一个trait中声明了若干方法:每一个方法或者仅是一个方法签名,或者带有默认实现
  3. // 2. 一个类型如果想要实现一个trait,则必须至少实现trait中的所有仅具有签名的方法
  4. // 3. 如果一个类型实现了特定的trait,
  5. // 则在这个类型的任何一个值上都可以使用trait中声明的方法
  6. // 下面这行代码表示:当前定义的特性的名称为Clone;且特性Sized是Clone的前置特性(supertrait)
  7. // 这里,前置特性的含义是:一个类型,若要实现特性A,则必须首先实现A的所有前置特性
  8. pub trait Clone: Sized {
  9. fn clone(&self) -> Self;
  10. // 以上语句声明了一个方法;该方法仅具有签名
  11. // 一个类型如果要实现Clone特性,则必须为这个方法提供实现
  12. //
  13. // 这个方法签名中,具有两个稍显奇怪的语法:Self和&self。其中:
  14. // 1. Self表示实现Clone特性的一个类型
  15. // 例如:如果我们要为bool类型实现Clone特性,则Self表示bool类型。
  16. // 因此,我们在一个bool类型的值调用clone方法,会返回一个bool类型的值
  17. // 2. &self是一种语法糖,其无糖形式是 self: &Self
  18. // 因此,&self表示clone方法具有一个类型为&Self的参数
  19. // 即:self一种引用类型的值;这个值是一个地址/指针,指向一个Self类型的值
  20. // 下面的这个方法具有默认实现
  21. // 一个类型在实现Clone特性时,如果认为这个默认实现不够好,则可以提供一个更好的实现;
  22. // 否则,无需再次实现该方法
  23. //
  24. // 这个方法实现的功能是:生成source值的一个拷贝,并把它赋值给self。
  25. // &mut self是一种语法糖,其无糖形式是 self: &mut Self
  26. // 即:self一种引用类型的值;这个值是一个地址/指针,指向一个Self类型的值
  27. // 同时,mut表示:我们可以通过self指针,修改其指向的那个Self类型的值
  28. fn clone_from(&mut self, source: &Self) {
  29. *self = source.clone()
  30. // 在上面这行代码中,方法调用source.clone()返回了一个Self类型的值
  31. // 然后,这个值被存放在self指针指向的内存位置。
  32. // *self也称为"去引用",即:通过一个指针访问到它指向的那个内存位置
  33. }
  34. }

下面给出了Rust为类型bool实现Clone特性的源代码:

  1. impl Clone for bool {
  2. #[inline]
  3. fn clone(&self) -> Self {
  4. *self
  5. }
  6. }
  7. // 在上面的代码中,方法clone的属性声明 #[inline] 告诉编译器:
  8. // 如果合适,请把clone方法内连(inline)到调用它的地方
  9. // 即:把方法调用替换为函数体中的等价代码,
  10. // 从而在运行时消除对clone方法的调用,提高程序的运行效率

既然bool类型已经实现了Clone特性,那么,我们就可以在任何一个bool类型的值上调用clone方法了。下面的代码示例给出调用clone方法的两种形式:

  1. #[allow(unused)]
  2. fn main() {
  3. let b: bool = true;
  4. let c1 = bool::clone(&b);
  5. // 上面的这行语句展示了在bool类型的值上调用clone方法的第一种形式:
  6. // 1. 首先,通过表达式bool::clone访问到bool实现的Clone特性中的clone方法
  7. // 2. 然后,按照clone方法的参数类型,向它传入实际参数&b
  8. // 3. 最后,clone(&b)方法调用返回b中值的一个拷贝,并将该拷贝赋给变量c1
  9. let c2 = b.clone();
  10. // 上面的这行语句展示了在bool类型的值上调用clone方法的第二种形式
  11. // 即:直接在b上通过点操作符访问到clone方法并调用
  12. // Rust中的点操作符很聪明:它会根据clone参数的类型,取得变量b的引用,并传入clone方法中
  13. //
  14. // 一个类型上附着的任何一个方法,
  15. // 如果它的第一个参数的名称是self,就可以使用点操作符的方式调用这个方法
  16. // 对于这两种调用方式,你偏向于哪一种呢?
  17. let c3 = b;
  18. // 在impl Clone for bool代码块中,我们请求编译器对bool类型值上的clone调用进行内连
  19. // 编译器在一般情况下,确实会进行内连。
  20. // 那么,对方法调用bool::clone(&b)进行内连的结果是什么呢?我们来看一下:
  21. // 1. 首先,用&b替换clone实现代码中的self,得到等价代码*&b
  22. // 2. 然后,对*&b进行进一步优化,得到等价代码b
  23. // 原来,我们对clone方法的调用只是调了一个寂寞!
  24. }

Copy

如果类型T实现了Copy特性,则对T的任何一个值v,只要把v值的二进制表示复制一遍,就可以得到v值的一个拷贝。与Sized特性类似,Copy也是一种标记型特性。下面给出了Copy特性的源代码:

  1. pub trait Copy: Clone { }
  2. // 可以看到:
  3. // 1. Clone是Copy特性的一个supertrait,
  4. // 即:一个类型,如果要实现Copy特性,必须要先实现Clone特性
  5. // 2. Copy特性中不包含任何成分,因此它是一种标记型特性

下面给出了Rust为bool类型实现Copy特性的源代码:

  1. impl Copy for bool {}
  2. // 实在无话可说

需要注意一点:即使一个类型实现了Clone特性,不代表它一定可以实现Copy特性。如果你为一个无法实现Copy特性的类型强行实现该特性,编译器会报出一个错误(Error)。 :::info 时机成熟后,我们再来介绍满足什么条件的类型才能实现Copy特性。 ::: 一个类型是否实现了Copy特性,对于该类型变量的赋值行为具有重大影响。

  • 给定类型为T的两个变量ts、以及一个赋值语句t = s;
    • 行为一:假设类型T实现了Copy特性,那么,这条语句在执行后
      1. s位置中的二进制串会被复制到t位置中
      2. s变量没有发生任何变化,我们可以继续从s位置读取其中的值。
    • 行为二:假设类型T没有实现Copy特性,那么,这条语句在执行后
      1. s位置中的二进制串会被复制到t位置中
      2. 然后,s变量处于未初始化(uninitialized)的状态;在没有为s重新赋值的情况下,我们无法再读取s的值。

第二种赋值行为称为带所有权转移的赋值行为。所有权是什么?这个问题暂且搁置。 :::info 为了叙述方便,在后文中,我们使用“Copy类型”表示“实现了Copy特性的类型”,使用“非Copy类型”表示“没有实现Copy特性的类型”。 :::

  • Copy类型和非Copy类型在赋值行为上的这种差异性,会贯穿Rust程序的方方面面
  • 如果可以,请把这种差异性深深地镌刻在你的Rust世界观中

下面,我们再介绍Rust为bool类型自动实现的其他若干特性。

Default

下面的代码块给出了Default特性的定义。如果类型T实现了Default特性,则我们可以通过在T上调用方法default,获取T的一个缺省值。

  1. pub trait Default {
  2. fn default() -> Self;
  3. }

下面的代码块给出了Rust为类型bool实现Default特性的源代码:

  1. impl const Default for bool { // const的含义是什么?这个问题暂且搁置
  2. #[inline]
  3. fn default() -> Self {
  4. false
  5. }
  6. }

下面的代码块给出了在类型bool上调用default方法的示例:

  1. #[allow(unused)]
  2. fn main() {
  3. let b = bool::default();
  4. // default方法的第一个参数不是self;因此,无法使用点操作符的方式调用该方法
  5. }

PartialEq

PartialEq特性的定义如下面的代码块所示。
PartialEq是一种范型特性(generic trait)。
我们可以从数学中函数的角度来看待范型特性。一个范型特性是一个函数:这个函数具有1到多个以类型为值的参数,返回一个特性。 :::info 注意:这里的函数指的是数学意义上的函数,而不是Rust中的函数。 ::: 对于PartialEq这种范型特性而言,它具有一个参数,名称为Rhs。同时,PartialEq还对Rhs的取值做了两点限制:

  1. 传入Rhs的类型,可以是一个定长类型,也可以是一个非定常类型。

    • 这种限制,在语法上表示为 Rhs: ?Sized :::info 在这个示例中,如果没有为范型参数Rhs声明?Sized,则要求Rhs必须是一个定长类型。
      这种约定(convention),对于Rust中其他地方出现的范型参数同样成立。 :::
  2. 如果没有为Rhs的传入一个类型,则Rhs具有一个缺省值Self,即:当前要实现PartialEq特性的那个类型

    • 这种限制,在语法上表示为 Rhs = Self

调用PartialEq返回的那个特性,包含两个方法。对这两个方法的描述,参见代码块中的注释。

  1. pub trait PartialEq<Rhs: ?Sized = Self> {
  2. // 该方法具有两个参数,返回一个bool类型的值
  3. // 该方法实现的功能是:判断两个参数的值是否相等;若相等,则返回true;否则,返回false
  4. // 该方法仅具有方法签名,需要实现PartialEq特性的类型提供该方法的实现
  5. fn eq(&self, other: &Rhs) -> bool;
  6. // 该方法具有两个参数,返回一个bool类型的值
  7. // 该方法实现的功能是:判断两个参数的值是否不相等
  8. // 该方法基于eq方法提供了一个缺省实现
  9. #[inline]
  10. fn ne(&self, other: &Rhs) -> bool {
  11. !self.eq(other)
  12. }
  13. }

Rust还要求:任何一个PartialEq实现,必须满足:a.eq(&b) XOR a.ne(&b) == true。但是,Rust没有使用任何机制对这种约束进行检查;一句话,全靠特性实现者的自觉 。

下面的代码块给出了Rust为类型bool实现PartialEq特性的源代码:

  1. // 在下面的这行代码中,我们调用了PartialEq,但是没有向它传入一个类型
  2. // 因此, PartialEq中的Rhs参数具有缺省值Self;在此处,Self为bool类型
  3. impl PartialEq for bool {
  4. #[inline]
  5. fn eq(&self, other: &Self) -> bool { (*self) == (*other) }
  6. #[inline]
  7. fn ne(&self, other: &Self) -> bool { (*self) != (*other) }
  8. }

有了这种实现,我们就可以在bool类型的值上调用PartialEq中的两个方法了。请看下面的代码示例:

  1. #[allow(unused)]
  2. fn main() {
  3. let t = true;
  4. let f = false;
  5. // 下面的三条语句展示了调用PartialEq特性中的eq方法的三种等价形式
  6. // 哪一种形式对程序员更为友好,一目了然
  7. let c0 = bool::eq(&t, &f);
  8. let c1 = t.eq(&f);
  9. let c2 = t == f;
  10. // 同理,下面的三条语句展示了调用PartialEq特性中的ne方法的三种等价形式
  11. let d0 = bool::ne(&t, &f);
  12. let d1 = t.ne(&f);
  13. let d2 = t != f;
  14. }

:::info Rust中的任何类型,只要它实现了PartialEq特性,就可以采用==!=操作符调用其中定义的eqne方法。这是Rust编译器给程序员带来的便利。 ::: 需要注意一点:Rust为类型bool实现的PartialEq特性中,范型参数Rhs取的是默认值Self;因此,我们只能通过这种PartialEq实现中的两个方法,比较两个bool类型的值是否相等。 :::info 那么,有没有可能为bool类型实现另外一种PartialEq特性,使得我们能够使用其中定义的eqne方法判断一个bool类型的值与一个其他类型的值是否相等呢?
如果你对这个问题有兴趣,可以自己查找相关的资料,寻找到答案。 ::: 下面,我们来介绍PartialEq特性所代表的物理含义。
PartialEq声明了一种偏等关系(partial equivalence relation)。称二元关系==为一个偏等关系,当且仅当如下两个性质成立:

  1. 对称性(Symmetric):如果a == b,则 b == a
  2. 传递性(Transitive):如果a == bb == c,则a == c

    如前所述,PartialEq特性的实现者应确保上述两个性质的满足。Rust编译器不会去检查(应该也没有能力去检查)这两个性质是否满足。

Eq

Eq声明了一种等价关系(equivalence relation)。称二元关系==为一个等价关系,当且仅当如下三个性质成立:

  1. 自反性(reflexive):a == a
  2. 对称性(Symmetric):如果a == b,则 b == a
  3. 传递性(Transitive):如果a == bb == c,则a == c

Eq特性的定义如下面的代码块所示:

  1. pub trait Eq: PartialEq<Self> { }

有上述定义可知:

  1. Eq特性中不包含任何方法
  2. Eq特性具有一个前置特性(supertrait),即:PartialEq<Self>
    • 这表示,若要为一个类型实现Eq特性,则该类型必须首先实现PartialEq<Self>特性

下面的代码块给出了Rust为类型bool实现Eq特性的源代码:

  1. impl Eq for bool {} // 无话可说

PartialOrd

PartialOrd特性的定义如下面的代码块所示。

  1. // PartialOrd是一个范型特性,具有一个范型参数Rhs
  2. // Rhs可以是一个定长参数,也可以是一个不定长参数
  3. // Rhs的缺省值是当前类型Self
  4. // PartialOrd<Rhs>具有一个supertrait:PartialEq<Rhs>
  5. // 也就是说:若要在类型T上实现PartialOrd<Rhs>特性,则类型T必须已经实现PartialEq<Rhs>特性
  6. pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
  7. fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
  8. #[inline]
  9. fn lt(&self, other: &Rhs) -> bool {
  10. matches!(self.partial_cmp(other), Some(Less))
  11. }
  12. #[inline]
  13. fn le(&self, other: &Rhs) -> bool {
  14. !matches!(self.partial_cmp(other), None | Some(Greater))
  15. }
  16. #[inline]
  17. fn gt(&self, other: &Rhs) -> bool {
  18. matches!(self.partial_cmp(other), Some(Greater))
  19. }
  20. #[inline]
  21. fn ge(&self, other: &Rhs) -> bool {
  22. matches!(self.partial_cmp(other), Some(Greater | Equal))
  23. }
  24. }

特性PartialOrd<Rhs>中声明了4个方法:

  • 第一个方法:fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>
    • 该方法的功能是判断两个值之间可能存在的顺序关系(>==、或<
    • 该方法的返回值类型为Option<Ordering>,用于表示一个可能存在的顺序关系
      • Option是Rust标准库中定义的一个范型枚举类型,其源码如下所示: ```rust // Option是一个范型枚举类型,具有一个范型参数T // Option具有两个变体(variant): // 1. None,表示没有值 // 2. Some(T),表示一个T类型的值,放在一个Some(…)形状的容器中

        [derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]

        pub enum Option { None, Some(T), }

// Option上的属性声明#[derive(X, Y, Z, …)]表示: // 请Rust编译器自动为类型Option实现X、Y、Z等列出的特性

  1. - `Ordering`也是Rust标准库中定义的一个枚举类型,其源码如下所示:
  2. ```rust
  3. // Ordering是一种枚举类型,具有三个变体:
  4. // 1. Less表示一个值小于另一个值
  5. // 2. Equal表示一个值等于另一个值
  6. // 3. Greater表示一个值大于另一个值
  7. #[derive(Clone, Copy, PartialEq, Debug, Hash)]
  8. #[repr(i8)]
  9. pub enum Ordering {
  10. Less = -1,
  11. Equal = 0,
  12. Greater = 1,
  13. }
  14. // Ordering上的属性声明#[repr(i8)]表示:请把Ordering类型的值在内存中表示为i8类型的值。
  15. // 每个变体后面的整数值,表示这个变体在内存中会被表示为这个i8类型的整数值
  • partial_cmp方法会判断传入的两个参数之间是否存在顺序关系
    • 如果不存在,则返回None
    • 如果存在,例如,第一个数小于第二个数,则返回Some(Less)
  • PartialOrd<Rhs>partial_cmp方法的实现必须与其前置特性PartialEq<Rhs>中eq方法的实现具有一致性
    • 即:对于两个值lrl.partial_cmp(&r) == Some(Equal) 当且仅当 l == r
      • 第二个方法:lt(&self, other: &Rhs) -> bool
  • 该方法的名称lt表示的含义是:less than
  • 该方法的功能是判断第一个参数是否小于第二个参数
  • 该方法提供了默认实现:matches!(self.partial_cmp(other), Some(Less))
    • 其中,matches是Rust标准库提供的一个宏,用于判断两个值是否具有相同的模式(pattern)
  • 若类型T实现了PartialOrd<Rhs>特性,给定T类型的一个值l、以及Rhs类型的一个值r,则存在三种调用lt方法的方式:
    1. T::lt(&l, &r)
    2. l.lt(&r)
    3. l < r // 显然,这种方式具有更好的可读性
      • 后面三个方法legtge的含义分别为less than or equal、greater than、greater than or equal。
  • 它们的实现和调用方式与lt方法类型,我们不再逐一解释

PartialOrd声明了一种偏序关系(partial order relation)。偏序关系在数学上具有严格的定义;我们不在此说明。Rust要求任何PartialOrd<Rhs>特性的实现都必须满足偏序关系的数学定义;然而,如前所述,Rust编译器不会去检查这种满足性。
下面的代码块给出了Rust为类型bool实现PartialOrd特性的源代码:

  1. impl PartialOrd for bool {
  2. #[inline]
  3. fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
  4. Some(self.cmp(other))
  5. // 这里的cmp是bool实现的另一个特性Ord定义的方法
  6. // 我们马上就要介绍Ord特性
  7. }
  8. }

Ord

特性Ord的定义如下面的代码块所示。

  1. //特性Ord具有两个前置特性:Eq和PartialOrd<Self>
  2. pub trait Ord: Eq + PartialOrd<Self> {
  3. fn cmp(&self, other: &Self) -> Ordering;
  4. #[inline]
  5. fn max(self, other: Self) -> Self
  6. where
  7. Self: Sized,
  8. {
  9. match cmp(&self, &other) {
  10. Ordering::Less | Ordering::Equal => v2,
  11. Ordering::Greater => v1,
  12. }
  13. }
  14. #[inline]
  15. fn min(self, other: Self) -> Self
  16. where
  17. Self: Sized,
  18. {
  19. match cmp(&self, &other) {
  20. Ordering::Less | Ordering::Equal => v1,
  21. Ordering::Greater => v2,
  22. }
  23. }
  24. fn clamp(self, min: Self, max: Self) -> Self
  25. where
  26. Self: Sized,
  27. {
  28. assert!(min <= max);
  29. if self < min {
  30. min
  31. } else if self > max {
  32. max
  33. } else {
  34. self
  35. }
  36. }
  37. }

Ord声明了一种严格序关系(strict order relation)。Ord特性的实现应该满足严格序的定义,且应该与其前置特性EqPartialOrd<Self>相关方法的实现保持一致。具体细节,可查看Rust官方文档。
下面的代码块给出了Rust为类型bool实现Ord特性的源代码:

  1. impl Ord for bool {
  2. #[inline]
  3. fn cmp(&self, other: &bool) -> Ordering {
  4. match (*self as i8) - (*other as i8) {
  5. -1 => Less,
  6. 0 => Equal,
  7. 1 => Greater,
  8. _ => unsafe { unreachable_unchecked() },
  9. }
  10. }
  11. }
  12. // 在上面的代码中,unreachable_unchecked函数的功能是:
  13. // 告诉编译器这个方法调用不可达,进而对相关代码做出优化

Not

特性Not的定义如下面的代码块所示:

  1. pub trait Not {
  2. type Output;
  3. fn not(self) -> Self::Output;
  4. }
  5. // 这个trait定义中出现了一种新的语法:关联类型(associated type)
  6. // 在上面的定义中,type OutPut; 语句声明了一个关联类型参数 Output
  7. // 任何Not特性的实现都需要为关联类型参数提供一个具体的类型

对于任何实现了Not特性的类型T、以及一个T类型的变量t,存在三种调用not方法的形式:

  1. T::not(t)
  2. t.not()
  3. !t;对于熟悉C/C++语言的开发者,这种形式具有更好的可读性

下面的代码块给出了Rust为类型bool实现Not特性的源代码:

  1. impl const Not for bool {
  2. type Output = bool;
  3. #[inline]
  4. fn not(self) -> bool { !self }
  5. }

你可能会隐约感受到Rust语言的一种风格:操作符的特性化(operator as trait method)。这种风格具有两个基本特点:

  1. 语言中出现的大部分操作符,都会对应到特定trait的某个方法上
    • 确实有一些特殊的操作符,无法对应到特定的方法上
    • 例如,具有短路行为的逻辑与/或操作符&&/||
  2. 一个合法的操作符表达式,等价于对应的方法调用表达式

操作符的特性化,具体一个重要作用,即:支持操作符的重载。如果要在一个自定义类型上支持某种操作符,只需要在这个类型上实现相应的特性即可。

适用于bool类型的操作符,都会对应到bool类型实现的某种特性的某个方法上。已经介绍过的这种对应关系包括:

  • 一元操作符!,对应于Not特性的not方法
  • 二元操作符==/!=,对应于Eq特性的eq/ne方法
  • 二元操作符</<=/>/>=,对应于PartialOrd特性的方法lt/le/gt/ge

类似地,适用于bool类型的其他一些操作符与特性方法的对应关系如下:

  • 二元操作符|,对应于BitOr特性的bitor方法
  • 二元操作符|=,对应于BitOrAssign特性的bitor_assign方法
  • 二元操作符&,对应于BitAnd特性的bitand方法
  • 二元操作符&=,对应于BitAndAssign特性的bitand_assign方法
  • 二元操作符^,对应于BitXor特性的bitxor方法
  • 二元操作符^=,对应于BitXorAssign特性的bitxor_assign方法

对于其中涉及的特性,我们就不再进行介绍了。有兴趣的同学,可以自己阅读相关资料。

数字类型

Rust提供了一组定长的数字类型,具体可分为整数类型浮点类型两类。

整数类型(Integer Type)

类型名 可表示的最小值 可表示的最大值
无符号
整数类型
u8
u16
u32
u64
u128
usize
有符号
整数类型
i8
i16
i32
i64
i128
isize

浮点类型(Floating-Point Type)