수색…


비고

특히 분산 환경 (예 : Apache Spark )에서 직렬화 문제를 피하려면 유형 클래스 인스턴스에 대해 Serializable 특성을 구현하는 것이 가장 좋습니다.

단순 유형 클래스

유형 클래스는 하나 이상의 유형 매개 변수가있는 단순한 trait 입니다.

trait Show[A] {
  def show(a: A): String
}

형식 클래스를 확장하는 대신 지원되는 각 형식에 대해 형식 클래스의 암시 적 인스턴스가 제공됩니다. 이러한 구현을 형식 클래스의 컴패니언 개체에 배치하면 특별한 가져 오기없이 암시 적 해결책을 사용할 수 있습니다.

object Show {
  implicit val intShow: Show[Int] = new Show {
    def show(x: Int): String = x.toString
  }

  implicit val dateShow: Show[java.util.Date] = new Show {
    def show(x: java.util.Date): String = x.getTime.toString
  }

  // ..etc
}

함수에 전달 된 일반 매개 변수에 유형 클래스의 인스턴스가 있음을 보장하려면 암시 ​​적 매개 변수를 사용하십시오.

def log[A](a: A)(implicit showInstance: Show[A]): Unit = {
  println(showInstance.show(a))
}

컨텍스트 바운드를 사용할 수도 있습니다.

def log[A: Show](a: A): Unit = {
  println(implicitly[Show[A]].show(a))
}

다른 메소드와 마찬가지로 위의 log 메소드를 호출하십시오. 암시 경우 컴파일 할 수 없게됩니다 Show[A] 구현이 발견되지 않는 수 A 당신을 통과 log

log(10) // prints: "10"
log(new java.util.Date(1469491668401L) // prints: "1469491668401"
log(List(1,2,3)) // fails to compile with
                 // could not find implicit value for evidence parameter of type Show[List[Int]]

이 예제에서는 Show 유형 클래스를 구현합니다. 임의의 형태의 임의의 인스턴스를 String 로 변환하기 위해서 사용되는 공통의 형태 클래스입니다. 모든 객체에 toString 메서드가 있지만 toString 이 유용한 방식으로 정의되었는지 여부는 항상 명확하지 않습니다. Show 유형 클래스를 사용하면 log 전달 된 모든 내용이 String 잘 변환 된 것을 보장 할 수 있습니다.

타입 클래스 확장하기

이 예제는 아래의 type 클래스를 확장하는 것에 대해 설명합니다.

trait Show[A] {
  def show: String
}

제어하는 클래스를 만들려면 (그리고 스칼라로 작성) 타입 클래스를 확장, 그 동반자 개체에 대한 암시를 추가합니다. 이 예제 에서 Person 클래스를 가져와 Show 를 확장하는 방법을 보여 드리겠습니다.

class Person(val fullName: String) {    
  def this(firstName: String, lastName: String) = this(s"$firstName $lastName")
}

우리는이 클래스를 Person 의 companion 객체에 암시 적으로 추가하여 Show 를 확장하도록 만들 수 있습니다 :

object Person {
  implicit val personShow: Show[Person] = new Show {
    def show(p: Person): String = s"Person(${p.fullname})"
  }
}

동반자 객체 클래스 와 동일한 파일에 있어야하므로 class Personobject Person 이 모두 동일한 파일에 있어야합니다.

스칼라에서 제어하지 않거나 작성하지 않은 클래스를 만들려면 Simple 클래스 Class 예제에서와 같이 type 클래스를 확장하고 type 클래스의 companion 객체에 암시 적을 추가합니다.

클래스 나 유형 클래스를 모두 제어하지 않으면 위의 것과 같이 암시 적으로 생성하고 import . Simple Type Class 예제 에서 log 메소드 사용 :

object MyShow {
  implicit val personShow: Show[Person] = new Show {
    def show(p: Person): String = s"Person(${p.fullname})"
  }
}

def logPeople(persons: Person*): Unit = {
  import MyShow.personShow
  persons foreach { p => log(p) }
}

유형에 유형 클래스 함수 추가

스칼라의 타입 클래스 구현은 다소 장황하다. 자세한 정보를 줄이는 한 가지 방법은 소위 "작업 클래스"를 도입하는 것입니다. 이러한 클래스는 기능을 확장하기 위해 변수 / 값을 가져올 때 변수 / 값을 자동으로 래핑합니다.

이것을 설명하기 위해 먼저 간단한 유형 클래스를 만듭니다.

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

다음으로 특성을 구현합니다 (유형 클래스를 인스턴스화합니다).

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) . 따라서 Addable 을 구현하는 유형을 항상 감싸는 "Operation Class"( "Ops Class"라고도 함)를 만들 것입니다.

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

이제 새로운 함수 addIntString 일부로 사용할 수 있습니다.

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

  }
}

"Ops"클래스는 시뮬라크르 룸 라이브러리의 매크로에 의해 자동으로 생성 될 수 있습니다 :

import simulacrum._

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


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow