20

因此,我向同事/朋友展示了 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

这不是最好的例子,回想起来我希望我能想出一个更好的例子。在向他展示后,他用一个反例作为回应,并询问 typeclass 模式实际上带来了什么好处:

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% 的收益。当其他人使用它们时,我理解它们的实现和非常本地化的好处,但实际上简洁地解释它们是相当困难的。谁能帮我?也许扩展我的例子来真正展示好处。

4

2 回答 2

24

类型类捕获了追溯可扩展性的概念。使用静态方法重载,您必须在一个地方一次定义它们,但是使用类型类,您可以随时为任何模块中的任何新类型定义新实例。例如

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")))
}
于 2012-12-19T23:56:58.597 回答
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 版本。

于 2012-12-20T10:08:54.360 回答