ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 11장 - DSL 만들기
    Kotlin/코틀린인액션요약 2022. 9. 23. 00:01
    728x90

    11장에서 다루는 내용

    영역 특화 언어 만들기

    수신 객체 지정 람다 사용

    invoke 관례 사용

    기존 코틀린 DSL 예제

     

     

    API에서 DSL으로

    궁극적인 목표는 코드의 가독성과 유지 보수성을 좋게 유지하고자 합니다.

     

    코틀린이 지원하는 간결한 구문들

    - 확장 함수

    - 중위 호출

    - 연산자 오버로딩

    - get 메서드에 대한 관례

    - 람다를 괄호 밖으로 빼내는 관례

    - 수신 객체 지정 람다

     

    코틀린 DSL도 온전히 컴파일 시점에 타입이 정해져서 모든 정적 타입 지정 언어의 장점을 얻을 수 있습니다.

     

    영역 특화 언어라는 개념

    우리에 가장 친숙한 DSL을 SQL과 정규식입니다.

    이런 DSL을 사용하게 되면 범용 언어를 사용하는 경우보다 특정 영역에 대한 연산을 더 간결하게 기술할 수 있습니다.

     

    하지만 범용 애플리케이션과 함께 조합하기 어렵고, DSL 언어에 대해서도 학습해야 합니다.

    이런 문제를 해결하고자 내부 DSL이라는 개념을 도입하고자 합니다.

     

    내부 DSL

    DSL의 핵심 장점을 유지하면서 특정 영역을 위해서 만들어졌지만 범용 언어와 동일한 문법을 사용합니다.

     

    예를 들어 HTML을 생성하는 DSL이 존재합니다.

    fun createSimpleTable() = createHTML().
    	table{
    		tr{
    			td{ + "cell"}
    		}
    	}

    내부 DSL을 사용하면 td를 tf안에만 사용할 수 있도록 강제합니다 (컴파일 에러)

    표 내부에 코틀린 코드를 원하는 대로 사용할 수 있습니다.

     

    수신 객체 지정 람다와 확장 함수 타입

    람다를 인자로 받는 buildString() 정의하기

    fun buildString(
    	builderAction: (StringBuilder) -> Unit
    	) : String{
    	val sb = StringBuilder()
    	builderAction(sb)
    	return sb.toString()
    }
    
    val s = buildString(
    	it.append("Hello, ")
    	it.append("World!")
    )

    하지만 일일이 it을 넣는 것을 불편합니다.

     

    builderAction : StringBuilder.() -> Unit 으로 변경하게 되면 it.append() 대신 append()를 사용할 수 있습니다.

     

     invoke 관례를 사용한 더 유연한 블록 중첩

    class Greeter(val greeting: String){
    	operator fun invoke(name : String){
    		println("$greeting, $name!")
        }
    }
    
    val bavarianGreeter = Greeter("Servus")
    bavarianGreeter("Dmitry")
    //출력 Servus, Dmitry!

    baviranGreeter는 내부적으로 bavarianGretter.invoke로 컴파일됩니다.

     

    실전 코틀린 DSL

    중위 호출 연쇄 : 테스트 프레임워크의 should

    원시 타입에 대한 확장 함수 정의 : 날짜 처리

    SQL을 위한 내부 DSL

     

     

    댓글

Designed by Tistory.