Rust中的traits和Haskell中的类型类有什么区别?

What is the difference between traits in Rust and typeclasses in Haskell?

铁锈的特征看起来至少表面上类似于哈斯克尔的类型分类,但是我看到人们写到它们之间有一些区别。我想知道这些区别到底是什么。


在基本层面上,没有太大的区别,但它们仍然存在。

haskell将typeclass中定义的函数或值描述为"methods",就像traits在它们所包含的对象中描述oop方法一样。但是,haskell处理这些问题的方式不同,将它们视为单个值,而不是像OOP那样将它们固定到对象上。这是最明显的表面水平差异。

直到最近,Rust做不到的一件事是高阶类型的特性,比如臭名昭著的FunctorMonad类型。

这意味着铁锈特性只能描述通常所说的"具体类型",换句话说,一个没有一般性论据的类型。但是,haskell可以生成使用类似于高阶函数如何使用其他函数的类型的高阶类型类,使用一个函数来描述另一个函数。我们不能在Rust中实现前面提到的类型类,因为它不支持在Haskell中被认为是基本的甚至是必要的这个特性。值得庆幸的是,这一点最近在相关项目中得到了实施。*然而,这并不是惯用的铁锈,通常被认为是"黑客"。

正如评论中所说,还可以提到,ghc(haskell的主要编译器)支持类型类的进一步选项,包括多参数(即涉及的许多类型)类型类和函数依赖性,这是一个允许类型级计算的可爱选项,并导致类型族。据我所知,Rust既没有眼底,也没有类型家族,尽管它可能在未来。

总的来说,虽然特征和类型类表面上看起来是等价的,但在考虑众多的品质时,如果比较深入,它们确实有很多不同。

*另一方面,斯威夫特,尽管有特点,却没有这样高的分型机制。可能是语言的未来更新?

?这里有一篇关于haskell的字体类(包括更高级的字体类)的好文章,还有一篇关于rust特性的同样好的文章被保存在这里,不过不幸的是有点过时了。


我认为目前的答案忽略了铁锈特性和哈斯克尔类型之间最根本的区别。这些差异与特征与面向对象的语言结构相关的方式有关。有关这方面的信息,请参阅铁锈书。

  • 特性声明创建特性类型。这意味着您可以声明此类类型的变量(或者更确切地说,类型的引用)。您还可以使用特征类型作为函数、结构字段和类型参数实例化的参数。

    只要被引用对象的运行时类型实现了特征,特征引用变量在运行时可以包含不同类型的对象。

    1
    2
    3
    4
    5
    6
    // The shape variable might contain a Square or a Circle,
    // we don't know until runtime
    let shape: &Shape = get_unknown_shape();

    // Might contain different kinds of shapes at the same time
    let shapes: Vec<&Shape> = get_shapes();

    这不是类型类的工作方式。类型类不创建类型,因此不能用类名声明变量。类型类充当类型参数的边界,但类型参数必须用具体类型而不是类型类本身实例化。

    不能有实现同一类型类的不同类型的不同事物的列表。(相反,haskell使用存在主义类型来表达类似的东西。)注1

  • 特征方法可以动态调度。这与上面的项目符号中描述的内容密切相关。

    动态调度意味着使用引用点的对象的运行时类型来确定通过引用调用的方法。

    1
    2
    3
    4
    5
    let shape: &Shape = get_unknown_shape();

    // This calls a method, which might be Square.area or
    // Circle.area depending on the runtime type of shape
    print!("Area: {}", shape.area());

    同样,在Haskell中也使用了存在主义类型。

  • 总结

    在我看来,特征基本上和类型类是相同的概念。此外,它们还具有面向对象接口的功能。

    (haskell的类型类更高级,因为haskell具有更高的类类型和扩展,比如多参数类型类。但我认为它们本质上是相同的。)

    注1:Rust的最新版本有一个更新来区分特性名称作为类型的用法和特性名称作为边界的用法。在特征类型中,名称的前缀是dyn关键字。有关更多信息,请参见此答案的示例。


    Rust的"特性"类似于Haskell的类型分类。

    与haskell的主要区别在于,特征只会影响带点符号的表达式,即A.foo(b)形式的表达式。

    Haskell类型类扩展到高阶类型。Rust特性不支持高阶类型,因为它们在整个语言中都是缺失的,也就是说,特性和类型类之间没有哲学上的区别。