Rust 类型操作

类型 特征 泛型

  • 允许用户自定义类型,以避免冗余代码

类型 与 特征

类型

  • 一组具有给定语义、布局等等
类型
u8{ 0u8, 1u8, ..., 255u8 }
char{ 'a', 'b', ... '🦀' }
struct S(u8, char){ (0u8, 'a'), ... (255u8, '🦀') }

类型等价与转换

  • 这可能很明显,但 u8&u8&mut u8,彼此完全不同
  • 任何 t: T 仅接受来自准确的 T 值,如
    • f(0_u8) 不能被 f(&0_u8) 调用
    • f(&mut my_u8) 不能被 f(&my_u8) 调用
    • f(0_u8) 不能被 f(0_i8) 调用

*在数学意义上,从类型的角度来看 0 != 0,在语言意义上,==(0u8, 0u16) 仅为了阻止一些小意外而没有定义

类型
u8{ 0u8, 1u8, ..., 255u8 }
u16{ 0u16, 1u16, ..., 65_535u16 }
&u8 { 0xffaa&u8, 0xffbb&u8, ... }
&mut u8{ 0xffaa&mut u8, 0xffbb&mut u8, ... }
  • 然而,Rust 有时可能有助于在类型之间进行转换
    • casts手动转换类型的值,0_i8 as u8
    • coercions安全时自动转换类型, let x: &u8 = &mut 0_u8;
  1. castscoercions强制转换将一个集合(如 u8)的值转换到另一个集合(如 u16),可能会添加 CPU 指令来完成此操作;这与子类型不同,意味着类型和子类型是同一个集合的一部分(如 u8u16 的子类型,跟 0_u80_u16 类似),而这种转换将纯粹是编译时检查。Rust并不对常规类型使用子类型(0_u80_u16 确实不同),而是对生命周期使用某种类型。
  2. 这里的安全不仅仅是物理概念(如 &u8 不能被强制转换为 &u128),还包括“历史表明这样的转换是否会导致编程错误”。

Implementations — impl S { }

impl Port {
    fn f() { ... }
}
  • 类型通常伴随着实现,如 impl Port {},与类型相关的行为有:
    • 相关函数 Port::new(80)
    • 方法 port.close()

*与之相关的更多的是哲学而不是技术,没有什么(除了好的品味)可以阻止 u8::play_sound() 的发生。

特征 — trait T { }

⌾ Copy ⌾ Clone ⌾ Sized ⌾ ShowHex

  • Traits ...
    • 是“抽象”行为的方式
    • trait 作者在语义上声明这个 trait 意味着 X
    • 其他人可以为他们的类型实现该行为
  • 将 trait 视为类型的“成员列表”:
Copy TraitClone TraitSized Trait
SelfSelfSelf
u8u8char
u16StringPort
.........
trait 作为成员表,Self 是指包含的类型
  • 属于该成员名单的任何人都将遵守名单的行为
  • Traits 还可以包括相关的方法、函数、...
trait ShowHex {
    // Must be implemented according to documentation.
    fn as_hex() -> String;

    // Provided by trait author.
    fn print_hex() {}
}

⌾ Copy

trait Copy { }
  • 没有方法的特征通常被称为marker traits
  • Copy 是标记特征的例子,意味着内存可以按位复制

⌾ Sized

  • 完全在明确控制外的一些 traits
  • Sized 由已知大小类型的编译器提供,要么是,要么不是

Implementing Traits for Types — impl T for S { }

impl ShowHex for Port { ... }
  • 特征是在'at some point'时为类型实现的
  • impl A for B 添加类型 B 到 trait 成员列表:
ShowHex Trait
Self
Port
  • 从表面上看,你可以认为该类型因其成员资格而获得“badge”
u8DevicePort
impl { ... }impl { ... }impl { ... }
⌾Sized⌾Transport⌾Sized
⌾Clone⌾Clone
⌾Copy⌾ShowHex

特征与接口

接口

  • Java 中,用户Alice创建接口 Eat
  • 当用户Bob创建新类型 Venison,他必须决定是否让新类型实现 Eat
  • 换句话说,所有成员资格必须在类型定义期间详尽地说明
  • 当使用新类型 Venison 时,用户Santa可以利用 Eat 提供的以下行为:
// Santa imports `Venison` to create it, can `eat()` if he wants.
import food.Venison;

new Venison("rudolph").eat();

特征

  • Rust 中,用户Alice创建特征 Eat
  • 用户Bob创建新类型 Venison,并且决定不去实现 Eat,他可能甚至都不知道 Eat 的存在
  • 某用户后来决定添加 EatVenison 将是一个非常好的主意
  • 当使用 Venison 时,用户Santa必须单独导入 Eat
// Santa needs to import `Venison` to create it, and import `Eat` for trait method.
use food::Venison;
use tasks::Eat;

// Ho ho ho
Venison::new("rudolph").eat();

*为了防止两个人实现不同的 Eat,Rust 编译器将限制选择为 Alice 或 Bob 其中的一个, 也就是说 impl Eat for Venison 可能只发生在 Venison crate 或 Eat crate 中。