在scala中使用类型类的缺点

时间:2014-03-21 18:36:21

标签: scala typeclass static-typing

有些框架完全包含了类型类模式。斯卡拉兹和无形将是很好的例子。所以肯定有些情况下类型类比普通的java类和多态更可取。

我敬畏证据表达能力,我很好奇为什么这种方法缺乏实际应用。是什么原因迫使scala程序员使用基本类。类型组明显地花费了冗长和运行时间,但还有其他原因吗?

我在没有Java经验的情况下来到scala,并且想知道我是否错过了经典scala-java类可能带来的一些重要好处。

我正在寻找一些显着的用例,显示类型不足或无效的区域。

1 个答案:

答案 0 :(得分:4)

类型类和继承允许以不同方式重用。继承擅长为更改的内部提供正确的功能。

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,即使他们只知道该类型是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" } 进行排序的内容。但是,如果您想按名称长度排序而不是标准排序呢?那么,

{{1}}

这很快变得无望,特别是因为你必须追捕Foo的所有子类并确保它们正确更新。你最好不要将小于计算推迟到一个类型类,你可以根据需要换掉它。 (或者对于必须始终明确引用的常规类。)这种自动选择的功能也是一个大问题。

你无法真正替换另一个。当您需要轻松地将新类型的数据合并到固定接口时,请使用继承。当您需要几种底层数据但需要轻松提供新功能时,请使用类型类。当你需要两者时,无论你采用哪种方式,你都会有很多工作要做,所以要品尝一下。