2 minute read

스칼라의 타입 클래스 패턴 정리

스칼라 타입 클래스 패턴은 3가지다.

  1. 타입 클래스
  2. 타입 클래스 인스턴스
  3. 타입 클래스 인터페이스(메서드)
    1. 3번 대신 인터페이스 신택스를 사용할 수 있다.

 

1. 타입 클래스

일단 이건 JSON 추상문법트리를 나타낸 것이다.

sealed trait Json
final case class JsObject(get: Map[String, Json]) extends Json
final case class JsString(get: String)            extends Json
final case class JsNumber(get: Double)            extends Json
case object JsNull    

이 trait가 타입 클래스이다. “JSON으로 직렬화하기”라는 행동을 나타낸다.

trait JsonWriter[A] {
  def write(value: A): Json
}

 

2. 타입 클래스 인스턴스

타입 클래스 인스턴스는 타입 클래스를 구체적인 타입(ex: String, Person)을 가지고 구현한거다.

implicit 키워드를 앞에 붙인다.

final case class Person(name: String, email: String)
 
object JsonWriterInstances {
  implicit val stringWriter: JsonWriter[String] =
    new JsonWriter[String] {
      def write(value: String): Json = JsString(value)
    }
 
  implicit val personWriter: JsonWriter[Person] =
    new JsonWriter[Person] {
      def write(value: Person): Json =
        JsObject(
          Map(
            "name"  -> JsString(value.name),
            "email" -> JsString(value.email)
          )
        )
    }
}

 

3. 타입 클래스 인터페이스

사용자가 사용할 기능을 나타낸다.

타입 클래스 인스턴스를 implicit 매개변수로 받는다.

object Json {
  def toJson[A](value: A)(implicit w: JsonWriter[A]): Json =
    w.write(value)
}

이렇게 사용한다.

import JsonWriterInstances._
 
Json.toJson(Person("Dave", "dave@example.com"))

 

4. 인터페이스 신택스

기존 타입에 메서드를 확장할 때 쓴다.

자바 String같이 상속 불가능한 final 타입에 메서드를 추가할 때 쓸 수 있다.

object JsonSyntax {
  implicit class JsonWriterOps[A](value: A) {
    def toJson(implicit w: JsonWriter[A]): Json =
      w.write(value)
  }
}

이렇게 사용한다.

import JsonWriterInstances._
import JsonSyntax._
 
Person("Yongjin", "yongjin@example.com").toJson

 

추가로

아래처럼 생긴 implicitly 함수로 implicit scope를 확인 가능하다.

def implicitly[A](implicit value: A): A = value

또한 implicit scope에 타입 클래스 인스턴스는 한 개만 있어야 컴파일러가 implicit 값을 잘 찾을 수 있다.(에러가 안 난다)

 

출처

https://underscore.io/books/scala-with-cats/