Rust特性是否类似于JavaScript mixins?

Ian*_*rth 3 rust

锈病书(第二版)认为,“特征类似于一个经常在其他语言中称为‘接口’功能,但有一些不同。” 对于那些不熟悉界面的人来说,这个比喻无法说明。是否可以将特征合理地认为是混合类(例如JavaScript中常见的混合类)?

两者似乎都是共享代码并向多个类型/对象添加方法而无需继承的一种方法,但是这些区别对于概念性理解有多重要?

Sch*_*ern 6

“特性”(或Perl中的“角色”)是一种将多个功能单元添加到类(或Rust中的struct)的方法,而没有多重继承的问题。特质是“跨领域关注点”,这意味着它们不属于类层次结构,可以在任何类上实现。

特性定义了一个接口,这意味着为了使任何东西实现该特性,它必须定义所有必需的方法。就像您可以要求方法参数属于某些类一样,您可以要求某些参数实现某些特征。

一个很好的例子是写输出。在许多语言中,您必须决定要写的是FileHandle对象还是Socket对象。这可能会令人沮丧,因为有时事情只会写入文件,而不会写入套接字,反之亦然,或者您可能希望捕获字符串中的输出以进行调试。

如果改为定义特征,则可以写入实现该特征的任何内容。这正是Rust所做的std::io::Write

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

    fn flush(&mut self) -> Result<()>;

    fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
        while !buf.is_empty() {
            match self.write(buf) {
                Ok(0) => return Err(Error::new(ErrorKind::WriteZero,
                                               "failed to write whole buffer")),
                Ok(n) => buf = &buf[n..],
                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }

    ...and a few more...
}
Run Code Online (Sandbox Code Playgroud)

任何想要实施的东西都Write 必须实施writeflush。提供了默认值write_all,但是您可以根据需要实现自己的默认值。

这是Vec<u8>实现方式,Write因此您可以“打印”到字节向量。

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

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.extend_from_slice(buf);
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
Run Code Online (Sandbox Code Playgroud)

现在,当您编写需要输出内容的内容而不是决定是否应将其写入一个File或一个TcpStream(网络套接字)或其他内容时,您会说它必须具有Write特征。

fn display( out: Write ) {
    out.write(...whatever...)
}
Run Code Online (Sandbox Code Playgroud)

Mixins是此版本的精简版。Mixins是注入到类中的方法的集合。就是这样 它们解决了多重继承和跨领域关注的问题,但解决的很少。接口没有正式的承诺,您只需调用方法并希望获得最好的接口即可。

Mixins在功能上大部分是等效的,但没有提供任何编译时检查以及特性所提供的高性能。

如果您熟悉mixin,那么特性将是组合功能的一种熟悉方式。定义接口的要求将是艰巨的,但是对于从JavaScript进入Rust的任何人来说,强类型将是一项艰巨的任务。


与JavaScript不同的是,mixins是一个简洁的插件,而traits是Rust的基本组成部分。它们使Rust成为强类型的,高性能的,非常安全的,而且非常灵活。特性使Rust可以对函数参数的有效性进行广泛的编译时检查,而无需强类型语言的传统限制。

Rust的许多核心部分都具有特征。std::io::Writer已经提到过。还有std::cmp::PartialEq哪个句柄==!=std::cmp::PartialOrd>>=<<=std::fmt::Display关于如何打印东西{}。等等。


01d*_*d55 3

将特质视为 mixins 会让你远离而不是走向理解。Traits 从根本上讲是关于严格的类型系统,这对于母语是 JavaScript 的程序员来说是相当陌生的。

与大多数编程结构一样,特征足够灵活,可以以类似于 mixins 惯用方式的方式使用它们,但这与大多数其他程序员(包括标准库)使用特征的方式完全不同。

你应该将特质视为一种彻底的新奇事物。