所以我向同事/朋友展示了Scala中类型类模式的一个例子。它看起来像这样:
case class Song(name: String, artist: String)
case class Address(street: String, number: Int)
trait LabelMaker[T] {
def output(t: T): String
}
object LabelMaker {
implicit object addressLabelMaker extends LabelMaker[Address] {
def output(address: Address) = {
address.number + " " + address.street + " street"
}
}
implicit object songLabelMaker extends LabelMaker[Song] {
def output(song: Song) = {
song.artist + " - " + song.name
}
}
def label[T : LabelMaker](t: T) = implicitly[LabelMaker[T]].output(t)
}
可以这样使用:
import LabelMaker._
println(label(new Song("Hey Ya", "Outkast"))) // Outkast - Hey Ya
println(label(new Address("Smithsonian", 273))) // 273 Smithsonian street
这不是最好的例子,回想起来,我希望我能想出一个更好的例子。在向他展示时,他回答了一个反例,并询问类型类模式实际带来的好处:
case class Song(name: String, artist: String)
case class Address(street: String, number: Int)
object LabelMaker {
def label(address: Address) = {
address.number + " " + address.street + " street"
}
def label(song: Song) = {
song.artist + " - " + song.name
}
}
import LabelMaker._
println(label(new Song("Hey Ya", "Outkast"))) // Outkast - Hey Ya
println(label(new Address("Smithsonian", 273))) // 273 Smithsonian street
我努力回答这个问题,这让我意识到我并不完全理解100%的收益。当其他人使用它们时,我理解它们的实现和非常本地化的好处,但实际上简洁地解释它们是非常困难的。谁能帮我?也许可以扩展我的榜样以真正展示其中的好处。
答案 0 :(得分:24)
类型类可以捕捉retroactive extensibility的概念。对于静态方法重载,您必须在一个位置同时定义它们,但是使用类型类,您可以随时为任何模块中的任何新类型定义新实例。 例如,
object LabelMaker {
// ... your original cases here ...
def label[T : LabelMaker](t: T) = implicitly[LabelMaker[T]].output(t)
}
// somewhere in future
object SomeModule {
import LabelMaker._
case class Car(title: String)
implicit object carLabelMaker extends LabelMaker[Car] {
def output(car: Car) = car.title
}
}
object Main extends App {
import LabelMaker._
import SomeModule._
println(label(Car("Mustang")))
}
答案 1 :(得分:0)
类型推断和类型组合:
implicit def tupleLabel[A: LabelMaker,B: LabelMaker] = new LabelMaker[(A,B)]{
def output(tuple: (A,B)) =
implicitly[Label[A]].label(tuple._1) + " and " + implicitly[Label[B]].label(tuple._2)
}
这显然很有用,并且不会在您的同事的Java版本中起作用。