向型別新增型別類函式

Scala 的型別類實現相當冗長。減少冗長的一種方法是引入所謂的操作類。這些類將在匯入變數/值時自動換行以擴充套件功能。

為了說明這一點,我們首先建立一個簡單的型別類:

// The mathematical definition of "Addable" is "Semigroup"
trait Addable[A] {
  def add(x: A, y: A): A
}

接下來我們將實現 trait(例項化型別類):

object Instances {

  // Instance for Int
  // Also called evidence object, meaning that this object saw that Int learned how to be added
  implicit object addableInt extends Addable[Int] {
    def add(x: Int, y: Int): Int = x + y
  }

  // Instance for String
  implicit object addableString extends Addable[String] {
    def add(x: String, y: String): String = x + y
  }

}

目前,使用我們的 Addable 例項非常麻煩:

import Instances._
val three = addableInt.add(1,2)

我們寧願寫下寫 1.add(2)。因此,我們將建立一個操作類(也稱為“Ops 類”),它將始終包裹實現 Addable 的型別。

object Ops {
  implicit class AddableOps[A](self: A)(implicit A: Addable[A]) {
    def add(other: A): A = A.add(self, other)
  }
}

現在我們可以使用我們的新功能 add,就好像它是 IntString 的一部分:

object Main {

  import Instances._ // import evidence objects into this scope
  import Ops._       // import the wrappers

  def main(args: Array[String]): Unit = {

    println(1.add(5))
    println("mag".add("net"))
    // println(1.add(3.141)) // Fails because we didn't create an instance for Double

  }
}

可以通過 simulacrum 庫中的巨集自動建立 Ops 類 :

import simulacrum._

@typeclass trait Addable[A] {
  @op("|+|") def add(x: A, y: A): A
}