std::default
),并且多参数特征排序工作(包括功能依赖性的类似物)起作用,尽管AFAIK仍需要解决特权的第一个参数。但是没有HKT。他们在遥遥无期的愿望清单上,但尚未出现。
std::default
),并且多参数特征排序工作(包括功能依赖性的类似物)起作用,尽管AFAIK仍需要解决特权的第一个参数。但是没有HKT。他们在遥遥无期的愿望清单上,但尚未出现。
Answers:
在基本级别上,没有太大区别,但它们仍然存在。
Haskell将在类型类中定义的函数或值描述为“方法”,就像特征在它们所包围的对象中描述OOP方法一样。但是,Haskell处理这些问题的方式有所不同,将它们视为单个值,而不是像OOP那样将它们固定到一个对象上。这是最明显的表面高度差异。
Rust暂时不能做的一件事是更高级别的输入特征,例如臭名昭著的Functor
和Monad
类型类。
这意味着Rust特征只能描述通常称为“混凝土类型”的特征,换句话说,没有通用参数的特征。Haskell从一开始就可以创建高阶类型类,它们使用的类型类似于高阶函数使用其他函数的方式:使用一个来描述另一个。一段时间以来,在Rust中这是不可能的,但是由于已经实现了相关项,因此这些特征变得司空见惯和惯用。
因此,如果我们忽略扩展名,它们并不完全相同,但是每个扩展名可以近似于另一个扩展名。
如评论中所述,还值得一提的是,GHC(Haskell的主要编译器)支持类型类的其他选项,包括多参数(即涉及的许多类型)类型类和函数依赖项,这是允许进行类型级计算的一个不错的选择。 ,并导致类型家庭。据我所知,Rust既没有funDeps也没有类型族,尽管将来可能没有。†
总而言之,特征和类型类具有根本的差异,这归因于它们之间的交互方式,使它们起作用并最终看起来非常相似。
†可以在此处找到有关Haskell的类型类(包括高类型类型)的一篇不错的文章,并且可以在此处找到有关特征的Rust by Example一章
我认为当前的答案忽略了Rust特征与Haskell类型类之间最根本的区别。这些差异与特征与面向对象的语言构造相关的方式有关。有关此信息,请参阅Rust书。
特征声明创建特征类型。这意味着您可以声明这种类型的变量(或更确切地说,该类型的引用)。您还可以将特征类型用作函数,结构字段和类型参数实例化的参数。
特征引用变量在运行时可以包含不同类型的对象,只要所引用对象的运行时类型实现该特征即可。
// 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
特质方法可以动态调度。这与上一节中描述的内容密切相关。
动态分配意味着引用指向的对象的运行时类型用于确定通过引用调用的方法。
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
关键字为前缀。例如,请参阅此答案以获取更多信息。
dyn Trait
为存在性类型的一种形式,因为它们与特征/类型类有关。我们可以考虑dyn
将运算符投影到类型上的边界,即dyn : List Bound -> Type
。将这个想法带到Haskell,并考虑到“这样就不能使用类名声明变量。”,我们可以在Haskell中间接进行此操作:data Dyn (c :: * -> Constraint) = forall (t :: Type). c t => D t
。定义好之后,我们可以使用[D True, D "abc", D 42] :: [D Show]
。
Rust的“特征”类似于Haskell的类型类。
与Haskell的主要区别在于,特征只对点标记的表达式(即a.foo(b)形式)进行干预。
Haskell类型类扩展到高阶类型。Rust特质仅不支持高阶类型,因为它们在整个语言中都是缺失的,即,这不是特质与类型类之间的哲学差异
Default
没有方法,仅与方法无关的功能的特征。
class Functor f where fmap :: (a -> b) -> (f a -> f b)
; 后者的一个例子是class Bounded a where maxBound :: a
。