《Rust 编程第一课》 学习笔记 day22

53 阅读2分钟

大家好,我是砸锅。一个摸鱼八年的后端开发。熟悉 Go、Lua。第二十二天还是继续和大家一起学习 Rust😊

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

trait 的定义

trait 是 Rust 的接口,定义了类型使用这个接口的行为,将数据结构的行为单独抽取出来,使其可以在多个类型之间共享,也可以作为约束,限制参数化类型必须符合它规定的行为

例如标准库的 std::io::Write

pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize>;
    fn flush(&mut self) -> Result<()>;

    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> { ... }
    fn is_write_vectored(&self) -> bool { ... }
    fn write_all(&mut self, buf: &[u8]) -> Result<()> { ... }
    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<()> { ... }
    fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()> { ... }
    fn by_ref(&mut self) -> &mut Self
    where
        Self: Sized,
    { ... }
}

这些方法也被称为关联函数,在上面这个 trait 里面,write 和 flush 都是必须实现的,其他都有缺省(默认)实现

Self 和 self

Self 表示当前类型,例如 File实现了 Write,那实现过程中用到的 Self 就是指 File

self 在用作方法的第一个参数时,实际就是 self::Self 的简写,所以 &self 等于 self: &Self,而 &mut self 等于 self: &mut Self

例如:

use std::fmt;
use std::io::Write;

struct BufBuilder {
    buf: Vec<u8>,
}

impl BufBuilder {
    pub fn new() -> Self {
        Self {
            buf: Vec::with_capacity(1024),
        }
    }
}

impl fmt::Debug for BufBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", String::from_utf8_lossy(self.buf.as_ref()))
    }
}

impl Write for BufBuilder {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.buf.extend_from_slice(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

fn main() {
    let mut buf = BufBuilder::new();
    buf.write_all(b"Hello world!").unwrap();
    println!("{:?}", buf);
}

代码里面实现了 write 和 flush 方法,其他的方法都是用缺省实现

在 Rust 里,如果无法在编译期给定一个具体类型,可以通过告诉编译器,此处需要且仅需要任何实现了这接口的数据类型,表现为 &dyn Trait 或者 Box ,这种类型叫做 Trait Object。这样就可以在运行时动态分派 (dynamic dispatching)

需要注意的是:如果 trait 所有的方法,返回值是 Self 或者携带泛型参数,那么这个 trait 就不能产生 trait object

在定义和使用 trait 时,需要遵循孤儿规则。也就是 trait 和实现 trait 的数据类型,至少有一个是当前 crate 中定义的,也就是不能为第三方的类型实现第三方的 trait

image.png

此文章为2月Day1学习笔记,内容来源于极客时间《Rust 编程第一课》