有些框架完全包含类型类模式。scalaz和无形的将是很好的例子。因此,在某些情况下,肯定有一些类型类比普通的Java类和多态性更好。
我敬畏隐含的证据表达能力,并且很好奇为什么这种方法缺乏实际应用。是什么原因迫使Scala程序员使用基本类。类型类显然在冗长和运行时上付出了代价,但是还有其他原因吗?
我是在没有Java经验的情况下来到Scala的,想知道我是否错过了经典Scala-java类可能提供的一些基本好处。
我正在寻找一些壮观的用例,以显示类型类不足或无效的领域。
类型类和继承以不同的方式实现重用。继承擅长为更改后的内部结构提供正确的功能。
class Foo { def foo: String = "foo" }
def fooUser(foo: Foo) { println(foo.foo) }
class Bar extends Foo {
private var annotation = List.empty[String]
def annotate(s: String) { annotation = s :: annotation }
override def foo = ("bar" :: annotation.map("@" + _)).mkString(" ")
}
现在,Foo
只要您给每个使用的人Bar
,即使他们只知道类型是a,也将能够获得正确的值Foo
。您不必预料到可能需要可插拔功能(除非未加上标签foo
final
)。您不需要跟踪类型,也不需要继续传递见证实例。您只要Bar
在需要的地方使用Foo
它,它就会做正确的事情。这是一个大问题。如果您想要一个固定的接口并具有易于修改的功能,继承就是您的事。
相反,当您具有一组固定的数据类型并具有易于修改的接口时,继承不是那么好。排序是一个很好的例子。假设您要排序Foo
。如果你试试
class Foo extends Sortable[Foo] {
def lt(you: Foo) = foo < you.foo
def foo = "foo"
}
您可以将其传递给可以排序的任何内容Sortable
。但是,如果您想按名称的长度而不是标准排序来排序呢?好,
class Foo extends LexicallySortable[Foo] with LengthSortable[Foo] {
def lexicalLt(you: Foo) = foo < you.foo
def lengthLt(you: Foo) = foo.length < you.foo.length
def foo = "foo"
}
这很快变得毫无希望,尤其是因为您必须查找Foo的所有子类并确保它们已正确更新。您最好将小于计算推迟到可以根据需要交换的类型类。(或者到常规类,您必须始终明确引用它。)这种自动选择的功能也很重要。
您不能真正用另一种替代。当您需要轻松地将新类型的数据合并到固定接口时,请使用继承。当您需要几种基础数据但又需要轻松提供新功能时,请使用类型类。当您同时需要两者时,无论您采用哪种方式,都将有大量工作要做,因此请尝试一下。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句