SQLãRegExpãGradle-ããããçµåãããã®ã¯äœã§ããïŒ ãããã¯ãã¹ãŠãå顿åèšèªãŸãã¯DSLïŒãã¡ã€ã³åºæèšèªïŒã®äœ¿çšäŸã§ãã ãã®ãããªåèšèªã¯ãããŒã¿ããŒã¹ããã®ããŒã¿ã®ã¯ãšãªãããã¹ãå
ã®äžèŽã®æ€çŽ¢ãã¢ããªã±ãŒã·ã§ã³ã®æ§ç¯ããã»ã¹ã®èšè¿°ãªã©ããã®çŠç¹ãçµãããã¿ã¹ã¯ã解決ããŸãã Kotlinèšèªã¯ãç¬èªã®å顿åèšèªãäœæããããã®å€æ°ã®å¯èœæ§ãæäŸããŸãã èšäºã®éçšã§ãããã°ã©ããŒã®æŠåšã«ã©ã®ããŒã«ãå«ãŸããŠããããææ¡ããææ¡ãããäž»é¡é åã«DSLãå®è£
ããŸãã
ãã®èšäºã§ç޹ä»ããæ§æå
šäœã«ã€ããŠãã§ããã ãç°¡åã«èª¬æããŸããããã®è³æã¯ãKotlinãå顿åèšèªãæ§ç¯ããããã®èšèªãšèŠãªããšã³ãžãã¢ãç·Žç¿ããããã«èšèšãããŠããŸãã èšäºã®çµããã«ãæºåããå¿
èŠãããæ¬ ç¹ã瀺ãããŸãã ãã®èšäºã§äœ¿çšãããŠããã³ãŒãã¯ãKotlinããŒãžã§ã³1.1.4-3ã«é¢é£ããŠãããGitHubã§å
¥æã§ããŸãã

DSLãšã¯äœã§ããïŒ
ããã°ã©ãã³ã°èšèªã¯ãæ±çšããã°ã©ãã³ã°èšèªãšãã¡ã€ã³åºæèšèªã®2çš®é¡ã«åé¡ã§ããŸãã DSLã®äžè¬çãªäŸã¯ãSQLãæ£èŠè¡šçŸãbuild.gradleã§ãã ãã®èšèªã¯æäŸãããæ©èœã®éãæžãããŸãããåæã«ç¹å®ã®åé¡ã广çã«è§£æ±ºããããšãã§ããŸãã ããã¯ãããã°ã©ã ãåœä»€åã¹ã¿ã€ã«ïŒçµæãååŸããæ¹æ³ïŒã§ã¯ãªãã宣èšåãŸãã¯å®£èšåã«è¿ãïŒçŸåšã®ã¿ã¹ã¯ãèšè¿°ããïŒã§èšè¿°ããæ¹æ³ã§ãããã®å Žåãåé¡ã®è§£æ±ºçã¯äžããããæ
å ±ã«åºã¥ããŠåŸãããŸãã
æšæºã®å®è¡ããã»ã¹ããããããã倿Žããã倿Žãããã§ããå ŽåããããŸãããäžè¬çã«ã¯ç°ãªãããŒã¿ãçµæã®åœ¢åŒã§ããã䜿çšããããšããŸãã DSLãäœæããããšã«ãããDSLã®ãšã³ããŠãŒã¶ãŒã¯ãœãªã¥ãŒã·ã§ã³ãã©ã®ããã«åŸãããããèããã«ãåãäž»é¡åéããããŸããŸãªåé¡ã解決ããããã®æè»ãªããŒã«ãäœæããŸãã ããã¯ããã€ãã®APIã§ãããããããå·§ã¿ã«äœ¿çšããŠã人çãšé·æçãªã·ã¹ãã ãµããŒãã倧å¹
ã«ç°¡çŽ åã§ããŸãã
ãã®èšäºã§ã¯ãKotlinèšèªã§ãå
éšãDSLãæ§ç¯ããããšãæ€èšããŸããã ãã®çš®ã®å顿åèšèªã¯ãæ±çšèšèªã®æ§æã«åºã¥ããŠå®è£
ãããŠããŸãã 詳现ã«ã€ããŠã¯ã ãã¡ããã芧ãã ãã ã
å¿çšåé
ç§ã®æèŠã§ã¯ãKotlin DSLãé©çšããŠå®èšŒããæè¯ã®æ¹æ³ã®1ã€ã¯ããã¹ãã«ãããã®ã§ãã
Javaã®äžçããæ¥ããšããŸãã ããªãå€§èŠæš¡ãªããŒã¿ã¢ãã«ã®ããã«ãæšæºãšã³ãã£ãã£ã€ã³ã¹ã¿ã³ã¹ãäœåºŠãäœåºŠãèšè¿°ããå¿
èŠããããŸãããïŒ ãã®ããã«ãããã€ãã®ãã«ããŒããŸãã¯ããã«æªãããšã«ãå
éšã®ããã©ã«ãå€ãåããç¹å¥ãªãŠãŒãã£ãªãã£ã¯ã©ã¹ã䜿çšããå¯èœæ§ããããŸããïŒ ãªãŒããŒããŒããããã¡ãœããã¯ããã€ãããŸããïŒ ã©ã®ãããã®é »åºŠã§ããã©ã«ãå€ããããããéžè±ããå¿
èŠããããŸããããŸããä»ã©ã®ãããã®äœæ¥ãããªããã°ãªããŸãããïŒ ãããã®è³ªåãåŠå®æ§ä»¥å€ã®äœãã®ã§ããªãå Žåã¯ãæ£ããèšäºãèªãã§ããŸãã
åæ§ã«ãæè²åéã«ç¹åããç§ãã¡ã®ãããžã§ã¯ãã§ã¯ããã«ããŒãšãŠãŒãã£ãªãã£ã¯ã©ã¹ã®å©ããåããŠãã·ã¹ãã ã®æãéèŠãªã¢ãžã¥ãŒã«ã®1ã€ã§ããã«ãªãã¥ã©ã ãæ§ç¯ããã¢ãžã¥ãŒã«ããã¹ãã§ã«ããŒããŸããã ãã®ã¢ãããŒãã¯ãèšç»ããã³æ€èšŒã·ã¹ãã ã®ããŸããŸãªã¢ããªã±ãŒã·ã§ã³ã®åœ¢æã®ããã«ãKotlinèšèªãšDSLã«çœ®ãæããããŸããã 以äžã«ããã®èšèªãã©ã®ããã«æŽ»çšããèšç»ãµãã·ã¹ãã ã®ãã¹ãã®éçºãæ·åããåã³ã«å€ããäŸã瀺ããŸãã
ãã®èšäºã§ã¯ãçåŸãšæåž«ãšã®éã®ã¯ã©ã¹èšç»ã®å°èŠæš¡ãªãã¢ã³ã¹ãã¬ãŒã·ã§ã³ã·ã¹ãã ããã¹ãããããã®DSLã®èšèšã«ã€ããŠèª¬æããŸãã
äž»ãªæ©èœ
Kotlinã®äž»ãªå©ç¹ããªã¹ãããŸããããããã«ããããã®èšèªã§ããªããããã«èšè¿°ã§ããç¬èªã®DSLãæ§ç¯ããããšãã§ããŸãã 以äžã¯ã䜿çšãã䟡å€ã®ããäž»èŠãªèšèªæ§æã®æ¹åç¹ã瀺ãã衚ã§ãã ãã®ãªã¹ããæ³šææ·±ã確èªããŠãã ããã ã»ãšãã©ã®ãã¶ã€ã³ãããç¥ããªãå Žåã¯ãé çªã«èªãããšããå§ãããŸãã ãã ãã1ã€ãŸãã¯2ã€ã®ãã€ã³ãã«æ
£ããŠããªãå Žåã¯ããããã«çŽæ¥ã¢ã¯ã»ã¹ã§ããŸãã ããã§ãã¹ãŠãããªãã¿ã§ããã°ãèšäºã®æåŸã§DSLã䜿çšããããšã®äžå©ãªç¹ã®ã¬ãã¥ãŒã«è¡ãããšãã§ããŸãã ãã®ãªã¹ããè£è¶³ãããå Žåã¯ãã³ã¡ã³ãã«ãªãã·ã§ã³ãèšå
¥ããŠãã ããã
æ©èœå | DSLæ§æ | éåžžã®æ§æ |
---|
æŒç®åã®ãªãŒããŒã©ã€ã | collection += element | collection.add(element) |
ã¿ã€ããšã€ãªã¢ã¹ | typealias Point = Pair<Int, Int> | 空ã®çžç¶äººã¯ã©ã¹ããã³ãã®ä»ã®æŸèæãäœæãã |
get / setã¡ãœããã®åæ | map["key"] = "value" | map.put("key", "value") |
è€æ°ã®å®£èš | val (x, y) = Point(0, 0) | val p = Point(0, 0); val x = p.first; val y = p.second |
ã«ãã³å€ã®ã©ã ã | list.forEach { ... } | list.forEach({...}) |
æ¡åŒµæ©èœ | mylist.first(); // first() mylist | ãŠãŒãã£ãªãã£é¢æ° |
æ¿å
¥æ©èœ | 1 to "one" | 1.to("one") |
ãã³ãã©ãŒä»ãã©ã ã | Person().apply { name = «John» } | ãã |
ã³ã³ããã¹ãå¶åŸ¡ | @DslMarker | ãã |
äœãæ°ããããšãèŠã€ããŸãããïŒ ããã§ã¯ç¶ããŸãããã
ãã®è¡šã§ã¯ãå§ä»»ãããããããã£ã¯æå³çã«çç¥ãããŠããŸããããã¯ãç§ã®æèŠã§ã¯ãDSLãæ€èšãã圢åŒã§DSLãæ§ç¯ããã®ã«åœ¹ç«ããªãããã§ãã ãããã®æ©èœã®ãããã§ãã³ãŒãã¯ãªãŒããŒãèšè¿°ããå€ãã®ããã€ãºã®å€ããæ§æãåãé€ããåæã«éçºãããã«æ¥œããããããšãã§ããŸãïŒãã©ãããã£ãšããïŒã Kotlin in Actionãšããæ¬ã®èªç¶èšèªã§ã®æ¯èŒãæ°ã«å
¥ããŸãããããšãã°ãè±èªã§ã¯ãæã¯åèªããæ§ç¯ãããææ³èŠåã¯åèªãã©ã®ããã«çµã¿åãããããå¶åŸ¡ããŸãã DSLã§ãåæ§ã«ã1ã€ã®æäœãè€æ°ã®ã¡ãœããåŒã³åºãã§æ§æã§ããåãã§ãã¯ã«ãããæ§é ãæå³ããªãããã«ãªããŸãã åœç¶ãåŒã³åºãã®é åºã¯å¿
ãããæããã§ã¯ãªããããããŸããããããã¯DSLèšèšè
ã®è¯å¿ã«æ®ããŸãã
ãã®èšäºã§ã¯ããå
éšDSLããã€ãŸã å顿åèšèªã¯ããŠãããŒãµã«èšèª-Kotlinã«åºã¥ããŠããŸãã
æçµçµæã®äŸ
å顿åèšèªã®æ§ç¯ãå§ããåã«ãèšäºãèªãã åŸã«æ§ç¯ã§ãããã®ã®çµæã瀺ããããšæããŸãã GitHubãªããžããªã«ãããã¹ãŠã®ã³ãŒãã¯ã ãã¡ãã«ãããŸã ã 以äžã¯ãèå³ã®ããç§ç®ã®çåŸã®æåž«æ€çŽ¢ããã¹ãããããã®DSLã§ãã ãã®äŸã§ã¯ãåºå®ã®ã¿ã€ã ã°ãªããããããã¯ã©ã¹ãæåž«ãšçåŸã®èšç»ã«åæã«é
眮ãããŠããããšã確èªããŸãã
schedule { data { startFrom("08:00") subjects("Russian", "Literature", "Algebra", "Geometry") student { name = "Ivanov" subjectIndexes(0, 2) } student { name = "Petrov" subjectIndexes(1, 3) } teacher { subjectIndexes(0, 1) availability { monday("08:00") wednesday("09:00", "16:00") } } teacher { subjectIndexes(2, 3) availability { thursday("08:00") + sameDay("11:00") + sameDay("14:00") } } // data { } doesn't be compiled here because there is scope control with // @DataContextMarker } assertions { for ((day, lesson, student, teacher) in scheduledEvents) { val teacherSchedule: Schedule = teacher.schedule teacherSchedule[day, lesson] shouldNotEqual null teacherSchedule[day, lesson]!!.student shouldEqual student val studentSchedule = student.schedule studentSchedule[day, lesson] shouldNotEqual null studentSchedule[day, lesson]!!.teacher shouldEqual teacher } } }
ããŒã«
DSLãæ§ç¯ããããã®ããŒã«ã®å®å
šãªãªã¹ãã¯äžèšã«ãããŸããã ãããã¯ããããäŸã§äœ¿çšãããŠããã åç
§ã«ããã³ãŒãã調ã¹ãããšã«ããããã®ãããªæ§é ã®æ§ç¯ã調ã¹ãããšãã§ããŸãã ãã®äŸã«äœåºŠãæ»ã£ãŠãããŸããŸãªããŒã«ã®ãã¢ãè¡ããŸãã DSLãæ§ç¯ããæ±ºå®ã¯æ¬è³ªçã«å®èšŒçã§ããããšã«æ³šæããããšãéèŠã§ããèªåã®ãããžã§ã¯ãã§èŠãããšãç¹°ãè¿ãããšãã§ããŸãããããã¯æç€ºããããªãã·ã§ã³ãå¯äžã®çã®éžæè¢ã§ããããšãæå³ããŸããã 以äžã§ã¯ãåããŒã«ã«ã€ããŠè©³ãã調ã¹ãŸãã
ãã®èšèªã®äžéšã®æ©èœã¯ä»ã®æ©èœãšã®çµã¿åããã§ç¹ã«åªããŠããããã®ãªã¹ãã®æåã®ããŒã«ã¯æ¬åŒ§ã®å€åŽã®ã©ã ãã§ãã
ã«ãã³å€ã®ã©ã ã
ããã¥ã¡ã³ã
ã©ã ãåŒãŸãã¯ã©ã ãã¯ã颿°ã«æž¡ããããä¿åããããåŒã³åºãããã§ããã³ãŒãã®ãããã¯ã§ãã Kotlinã§ã¯ãã©ã ãåã¯æ¬¡ã®ããã«ç€ºãããŸã( ) ->
ã ãã®èŠåã«åŸããšãã©ã ãã®æãåå§çãªåœ¢åŒã¯() -> Unit
ã§ãUnitã¯1ã€ã®äŸå€ãé€ããŠVoidã®é¡äŒŒç©ã§ãã ã©ã ããŸãã¯é¢æ°ã®çµããã§ã¯
ãreturn ...ãã³ã³ã¹ãã©ã¯ããèšè¿°ããå¿
èŠããããŸãã ãã®ãããåžžã«æ»ãå€ã®åããããŸããKotlinã§ã¯ããã¯æé»çã«è¡ãããŸãã
以äžã¯ãã©ã ãã倿°ã«ä¿åããæãç°¡åãªäŸã§ãã
val helloPrint: (String) -> Unit = { println(it) }
ãã©ã¡ãŒã¿ã®ãªãã©ã ãã®å Žåãã³ã³ãã€ã©ã¯æ¢ç¥ã®åããç¬ç«ããŠåãæŽŸçã§ããŸãã ãã ãããã®å Žåã1ã€ã®ãã©ã¡ãŒã¿ãŒããããŸãã ãã®ãããªã©ã ãã®åŒã³åºãã¯æ¬¡ã®ãšããã§ãã
helloPrint("Hello")
äžèšã®äŸã§ã¯ãlambdaã¯1ã€ã®ãã©ã¡ãŒã¿ãŒãåããŸãã ã©ã ãå
ã§ã¯ããã®ãã©ã¡ãŒã¿ãŒã¯ããã©ã«ãã§ãitããšããååã«ãªã£ãŠããŸãããè€æ°ã®ãã©ã¡ãŒã¿ãŒãããå Žåã¯ãååãæç€ºçã«ãªã¹ãããããã¢ã³ããŒã¹ã³ã¢ã_ãã䜿çšããŠç¡èŠããå¿
èŠããããŸãã æ¬¡ã®äŸã¯ããã®åäœã瀺ããŠããŸãã
val helloPrint: (String, Int) -> Unit = { _, _ -> println("Do nothing") } helloPrint("Does not matter", 42)
ããšãã°ãGroovyã§ãã§ã«èŠãåºæ¬çãªããŒã«ã¯ãæ¬åŒ§ã®å€åŽã®ã©ã ãã§ãã èšäºã®åé ã®äŸã«æ³šæããŠãã ãããæšæºèšèšãé€ããã»ãŒãã¹ãŠã®äžæ¬åŒ§ã®äœ¿çšã¯ã©ã ãã®äœ¿çšã§ãã x { ⊠}
圢åŒãäœæããã«ã¯ãå°ãªããšã2ã€ã®æ¹æ³ããããŸãã
- ãªããžã§ã¯ãxãšãã®åé
æŒç®ååŒã³åºãïŒãã®ã¡ãœããã«ã€ããŠã¯åŸã§èª¬æããŸãïŒã
- lambdaãæž¡ããã颿°xã
ãªãã·ã§ã³ã«é¢ä¿ãªããã©ã ãã䜿çšããŸãã 颿°x()
ãŸãã Kotlinèšèªã§ã¯ã次ã®ã«ãŒã«ãé©çšãããŸããã©ã ãã颿°ã®æåŸã®åŒæ°ã§ããå Žåãè§æ¬åŒ§ããå€ãããšãã§ããã©ã ããå¯äžã®ãã©ã¡ãŒã¿ãŒã§ããå Žåãè§æ¬åŒ§ãæžãããšã¯ã§ããŸããã ãã®çµæãæ§æx({âŠ})
ãx() {}
ã«å€æã§ããŸãããã®åŸãæ¬åŒ§ãåé€ãããšã x {}
åŸãããŸãã ãã®ãããªé¢æ°ã®å®£èšã¯æ¬¡ã®ãšããã§ãã
fun x( lambda: () -> Unit ) { lambda() }
ãŸãã¯åäžè¡é¢æ°ã®çç¥åœ¢ã§ããããæžãããšãã§ããŸãïŒ
fun x( lambda: () -> Unit ) = lambda()
ããããxãã¯ã©ã¹ã§ã¯ãªãããªããžã§ã¯ãã§ããã颿°ã§ã¯ãªãå Žåã¯ã©ãã§ããããïŒ å¥ã®è峿·±ã解決çããããŸããããã¯ãå顿åèšèªã®æ§ç¯ãæŒç®åã®åå®çŸ©ã§äœ¿çšãããåºæ¬æŠå¿µã®1ã€ã«åºã¥ããŠããŸãã ãã®ããŒã«ãèŠãŠã¿ãŸãããã
æŒç®åã®ãªãŒããŒã©ã€ã
ããã¥ã¡ã³ã
Kotlinã¯ãåºãã¯ãããéãããç¯å²ã®æŒç®åãæäŸããŸãã æŒç®å修食åã䜿çšãããšãç¹å®ã®æ¡ä»¶äžã§åŒã³åºãããèŠåã«ãã£ãŠé¢æ°ãå®çŸ©ã§ããŸãã æãããªäŸã¯ã2ã€ã®ãªããžã§ã¯ãéã§+æŒç®åã䜿çšãããšãã«å®è¡ãããplus颿°ã§ãã äžèšã®ããã¥ã¡ã³ãã®ãªã³ã¯ã§ãæŒç®åã®å®å
šãªãªã¹ããèŠã€ããããšãã§ããŸãã
å°ãããããªåŒã³åºãæŒç®åãèããŠãã ããã ãã®èšäºã®äž»ãªäŸã¯ãschedule {}æ§é ããå§ãŸããŸãã èšèšã®ç®çã¯ãèšç»ã®ãã¹ããæ
åœããã³ãŒããããã¯ãåé¢ããããšã§ãã ãã®ãããªæ§æãæ§ç¯ããã«ã¯ãäžèšã§æ€èšãããã®ãšã¯å°ãç°ãªãã¡ãœããã䜿çšãããŸããinvoke+ "lambda out of brackets"æŒç®åã§ãã invokeãªãã¬ãŒã¿ãŒãå®çŸ©ãããšãã¹ã±ãžã¥ãŒã«ïŒ...ïŒæ§é ã䜿çšå¯èœã«ãªããŸãããã¹ã±ãžã¥ãŒã«ã¯ãªããžã§ã¯ãã§ãã å®éãã¹ã±ãžã¥ãŒã«ïŒ...ïŒåŒã³åºãã¯ãã³ã³ãã€ã©ã«ãã£ãŠschedule.invokeïŒ...ïŒãšããŠè§£éãããŸãã ã¹ã±ãžã¥ãŒã«ã®å®£èšãèŠãŠã¿ãŸãããã
object schedule { operator fun invoke(init: SchedulingContext.() -> Unit) { SchedulingContext().init() } }
ã¹ã±ãžã¥ãŒã«èå¥åã¯ãç¹å¥ãªããŒã¯ãŒããªããžã§ã¯ãã§ããŒã¯ãããã¹ã±ãžã¥ãŒã«ã¯ã©ã¹ïŒã·ã³ã°ã«ãã³ïŒã®å¯äžã®ã€ã³ã¹ã¿ã³ã¹ã«éä¿¡ãããããšãçè§£ããå¿
èŠããããŸãïŒãã®ãããªãªããžã§ã¯ãã®è©³çްã«ã€ããŠã¯ã ãã¡ããåç
§ããŠãã ãã ïŒã ãããã£ãŠãã¹ã±ãžã¥ãŒã«ã€ã³ã¹ã¿ã³ã¹ã§invokeã¡ãœãããåŒã³åºããŸãããã®å Žåãã¡ãœãããžã®å¯äžã®ãã©ã¡ãŒã¿ãŒã¯ã©ã ãã§ããããããè§ãã£ãã§å²ã¿ãŸãã ãã®çµæãschedule {...}ã³ã³ã¹ãã©ã¯ãã¯æ¬¡ãšåçã§ãã
schedule.invoke( { } )
ãã ããinvokeã¡ãœãããããèŠããšãéåžžã®ã©ã ãã§ã¯ãªããããã³ãã©ãŒä»ãã©ã ãããŸãã¯ãã³ã³ããã¹ãä»ãã©ã ããã衚瀺ããããã®ã¿ã€ãã¯æ¬¡ã®ããã«èšè¿°ãããŸãïŒ SchedulingContext.() -> Unit
ãããäœã§ããããçè§£ããæã§ãã
ãã³ãã©ãŒä»ãã©ã ã
ããã¥ã¡ã³ã
Kotlinã¯ãã©ã ãåŒã®ã³ã³ããã¹ããèšå®ããæ©äŒãäžããŠãããŸãã ã³ã³ããã¹ãã¯éåžžââã®ãªããžã§ã¯ãã§ãã ã³ã³ããã¹ãã®ã¿ã€ãã¯ãã©ã ãåŒã®ã¿ã€ããšãšãã«æ±ºå®ãããŸãã ãã®ãããªã©ã ãã¯ãã³ã³ããã¹ãã¯ã©ã¹ã®ééçã¡ãœããã®ããããã£ãååŸããŸããããã®ã¯ã©ã¹ã®ãããªãã¯APIã®ã¿ã«ã¢ã¯ã»ã¹ã§ããŸãã
éåžžã®ã©ã ãã®ã¿ã€ãã¯æ¬¡ã®ããã«å®çŸ©ãããŸãïŒ () -> Unit
ãã¿ã€ãXã®ã³ã³ããã¹ããæã€ã©ã ãã®ã¿ã€ãã¯æ¬¡ã®ããã«å®çŸ©ãããŸãïŒ X.()-> Unit
ãããã³æåã®ã¿ã€ãã®ã©ã ããéåžžã®æ¹æ³ã§éå§ã§ããå ŽåïŒ
val x : () -> Unit = {} x()
次ã«ãã³ã³ããã¹ããæã€ã©ã ãã«ã¯ã³ã³ããã¹ããå¿
èŠã§ãïŒ
class MyContext val x : MyContext.() -> Unit = {} //x() // , .. val c = MyContext() // cx() // x(c) //
ã¹ã±ãžã¥ãŒã«ãªããžã§ã¯ãã§invokeæŒç®åãå®çŸ©ããããšãæãåºãããŠãã ããïŒåã®æ®µèœãåç
§ïŒãããã«ãããæ§é ã䜿çšã§ããŸãã
schedule { }
䜿çšããã©ã ãã«ã¯ãSchedulingContextã®ãããªã³ã³ããã¹ãããããŸãã ããŒã¿ã¡ãœããã¯ãã®ã¯ã©ã¹ã§å®çŸ©ãããŸãã ãã®çµæãæ¬¡ã®æ§é ãåŸãããŸãã
schedule { data { //... } }
ãæ³åã®ãšãããããŒã¿ã¡ãœããã¯ã³ã³ããã¹ããæã€ã©ã ãã䜿çšããŸãããã³ã³ããã¹ãã¯æ¢ã«ç°ãªããŸãã ãããã£ãŠãè€æ°ã®ã³ã³ããã¹ããåæã«äœ¿çšã§ããå
¥ãåæ§é ãååŸããŸãã
ãã®äŸãã©ã®ããã«æ©èœãããã詳现ã«çè§£ããããã«ããã¹ãŠã®æ§æç³ãåé€ããŸãããã
schedule.invoke({ this.data({ }) })
ã芧ã®ãšããããã¹ãŠãéåžžã«ç°¡åã§ãã
invokeã¹ããŒãã¡ã³ãã®å®è£
ãèŠãŠã¿ãŸãããã
operator fun invoke(init: SchedulingContext.() -> Unit) { SchedulingContext().init() }
ã³ã³ããã¹ãã®ã³ã³ã¹ãã©ã¯ã¿ãŒSchedulingContext()
ïŒãåŒã³åºããäœæããããªããžã§ã¯ãïŒã³ã³ããã¹ãïŒã§ããã©ã¡ãŒã¿ãŒãšããŠæž¡ããèå¥åinitã§ã©ã ããåŒã³åºããŸãã ããã¯ãéåžžã®é¢æ°ã®åŒã³åºãã«éåžžã«äŒŒãŠããŸãã ãã®çµæã SchedulingContext().init()
1è¡ã§ãã³ã³ããã¹ããäœæãããªãã¬ãŒã¿ãŒã«æž¡ãããã©ã ããåŒã³åºããŸãã ä»ã®äŸã«èå³ãããå Žåã¯ãé©çšã«æ³šæããKotlinæšæºã©ã€ãã©ãªã®ã¡ãœããã䜿çšããŠãã ããã
æåŸã®äŸã§ã¯ãinvokeæŒç®åãšãä»ã®ããŒã«ãšã®çžäºäœçšã調ã¹ãŸããã æ¬¡ã«ãæ£åŒã«ã¯æŒç®åã§ãããã³ãŒããç°¡æœã«ããå¥ã®ããŒã«ãã€ãŸãget / setã¡ãœããã®èŠåã«çŠç¹ãåœãŠãŸãã
get / setã¡ãœããã®åæ
ããã¥ã¡ã³ã
DSLãéçºãããšãã1ã€ä»¥äžã®ããŒã䜿çšããŠé£æ³é
åã«ã¢ã¯ã»ã¹ããããã®æ§æãå®è£
ã§ããŸãã 以äžã®äŸãèŠãŠãã ããã
availabilityTable[DayOfWeek.MONDAY, 0] = true println(availabilityTable[DayOfWeek.MONDAY, 0])
è§æ¬åŒ§ã䜿çšããã«ã¯ãæŒç®å修食åã䜿çšããŠãå¿
èŠãªãã®ïŒèªã¿åããŸãã¯æžã蟌ã¿ïŒã«å¿ããŠgetãŸãã¯setã¡ãœãããå®è£
ããå¿
èŠããããŸãã ãã®ããŒã«ã®å®è£
äŸã¯ã ãªã³ã¯ã® GitHubã®Matrixã¯ã©ã¹ã«ãããŸãã ããã¯ããããªãã¯ã¹ãæäœããããã®ã©ãããŒã®æãåçŽãªå®è£
ã§ãã 以äžã¯ãèå³ã®ããã³ãŒãã®äžéšã§ãã
class Matrix(...) { private val content: List<MutableList<T>> operator fun get(i: Int, j: Int) = content[i][j] operator fun set(i: Int, j: Int, value: T) { content[i][j] = value } }
getããã³set颿°ã®ãã©ã¡ãŒã¿ãŒã¿ã€ãã¯ãæ³ååã«ãã£ãŠã®ã¿å¶éãããŸãã get / set颿°ã«1ã€ãŸãã¯è€æ°ã®ãã©ã¡ãŒã¿ãŒã䜿çšããŠãããŒã¿ã«ã¢ã¯ã»ã¹ããããã®å¿«é©ãªæ§æãæäŸã§ããŸãã Kotlinã®ãªãã¬ãŒã¿ãŒã¯ãããã¥ã¡ã³ãã«èšèŒãããŠããå€ãã®è峿·±ãæ©èœãæäŸããŸãã
é©ããããšã«ãKotlinæšæºã©ã€ãã©ãªã«ã¯Pairã¯ã©ã¹ããããŸããããªãã§ããïŒ ã³ãã¥ããã£ã®å€§éšåã¯ãPairã¯ã©ã¹ãæªããšèããŠããŸããããã«ããã2ã€ã®ãªããžã§ã¯ãã®æ¥ç¶ã®æå³ããªããªãããããããã¢ã«ãªã£ãŠããçç±ãæããã«ãªããŸããã æ¬¡ã®2ã€ã®ããŒã«ã¯ãã«ããã«ã®æå³ãä¿åããäœåãªã¯ã©ã¹ãäœæããªãæ¹æ³ã瀺ããŠããŸãã
ã¿ã€ããšã€ãªã¢ã¹
ããã¥ã¡ã³ã
æŽæ°åº§æšãæã€å¹³é¢äžã®ç¹ã«ã©ãããŒã¯ã©ã¹ãå¿
èŠã ãšæ³åããŠãã ããã ååãšããŠã Pair<Int, Int>
ã¯ã©ã¹ã¯ç§ãã¡ã«é©ããŠããŸããããã®ã¿ã€ãã®å€æ°ã§ã¯ãå€ããã¢ã§ãã€ã³ãããçç±ã®çè§£ãäžæçã«å€±ãããå ŽåããããŸãã æãããªä¿®æ£ã¯ãç¬èªã®ã¯ã©ã¹ãäœæããããããã«æªãããšã§ãã Kotlinã§ã¯ãéçºè
ã®å
µåšåº«ã«ã¯ã次ã®ããã«èšè¿°ãããã¿ã€ããšã€ãªã¢ã¹ãè£å
ãããŸãã
typealias Point = Pair<Int,Int>
å®éãããã¯ã³ã³ã¹ãã©ã¯ãã®éåžžã®åå倿Žã§ãã ãã®ã¢ãããŒãã®ãããã§ãPointã¯ã©ã¹ãäœæããå¿
èŠã¯ãããŸããããã®å ŽåãåçŽã«ã«ããã«ãè€è£œããŸãã ããã§ã次ã®ããã«ãã€ã³ããäœæã§ããŸãã
val point = Point(0, 0)
ãã ããPairã¯ã©ã¹ã«ã¯2ã€ã®ããããã£ããããŸãã1ã€ç®ãš2ã€ç®ã§ãããããã®ããããã£ã®ååã倿ŽããŠãç®çã®Pointã¯ã©ã¹ãšPairã¯ã©ã¹ã®éããæ¶å»ããã«ã¯ã©ãããã°ããã§ããããã ããããã£èªäœã®ååã倿Žããããšã¯ã§ããŸããããããŒã«ãããã«ã¯ãè·äººãè€æ°ã®å®£èšãšããŠæå®ããçŽ æŽãããæ©äŒããããŸãã
è€æ°å®£èšïŒç Žå£å®£èšïŒ
ããã¥ã¡ã³ã
äŸã®çè§£ãç°¡åã«ããããã«ãç¶æ³ãèããŠã¿ãŸããããäžèšã®äŸãããããããã«ãPointåã®ãªããžã§ã¯ãããããããããã¯ååã倿ŽãããPair<Int, Int>
åã«ãããŸããã æšæºã©ã€ãã©ãªã®Pairã¯ã©ã¹ã®å®è£
ãããããããã«ãããŒã¿ä¿®é£Ÿåã§ããŒã¯ãããŠããŸããããã¯ããšãããããã®ã¯ã©ã¹ã§çæãããcomponentNã¡ãœãããååŸããããšãæå³ããŸãã ãããã«ã€ããŠè©±ããŸãããã
ã©ã®ã¯ã©ã¹ã«å¯ŸããŠããã³ã³ããŒãã³ãã®1ã€ã®ããããã£ãžã®ã¢ã¯ã»ã¹ãæäŸããcomponentNæŒç®åãå®çŸ©ã§ããŸãã ããã¯ãpoint.component1ã®åŒã³åºããpoint.firstã®åŒã³åºããšåçã§ããããšãæå³ããŸãã æ¬¡ã«ããã®è€è£œãå¿
èŠãªçç±ãèŠãŠã¿ãŸãããã
è€æ°å®£èšãšã¯äœã§ããïŒ ããã¯ããªããžã§ã¯ãã倿°ã«ãåè§£ãããæ¹æ³ã§ãã ãã®æ©èœã®ãããã§ãæ¬¡ã®æ§æãèšè¿°ã§ããŸãã
val (x, y) = Point(0, 0)
äžåºŠã«è€æ°ã®å€æ°ã宣èšããæ©äŒããããŸãããå€ãšããŠã¯ã©ããªããŸããïŒ ãã®ãããã·ãªã¢ã«çªå·ã«å¿ããŠcomponentN
ã®çæãããã¡ãœãããå¿
èŠã«ãªããŸããNã®ä»£ããã«ã1ããéå§ããŠããªããžã§ã¯ãããã®ããããã£ã®ã»ããã«åè§£ã§ããŸãã ãããã£ãŠãããšãã°ãäžèšã®ãšã³ããªã¯æ¬¡ãšåçã§ãã
val pair = Point(0, 0) val x = pair.component1() val y = pair.component2()
ããã¯æ¬¡ãšåçã§ãïŒ
val pair = Point(0, 0) val x = pair.first val y = pair.second
ããã§ãfirstãšsecondã¯Pointãªããžã§ã¯ãã®ããããã£ã§ãã
Kotlinã®forã³ã³ã¹ãã©ã¯ãã®åœ¢åŒã¯æ¬¡ã®ãšããã§ããxã¯å€1ã2ãããã³3ãé çªã«åãåããŸãã
for(x in listOf(1, 2, 3)) { ⊠}
äž»ãªäŸã®DSLã®assertions
ãããã¯ã«æ³šæããŠãã ããã 䟿å®äžããã®äžéšã以äžã«ç€ºããŸãã
for ((day, lesson, student, teacher) in scheduledEvents) { ⊠}
ããã§ãã¹ãŠãæããã«ãªããŸãã scheduleEventsã³ã¬ã¯ã·ã§ã³ãå埩åŠçããŸããåèŠçŽ ã¯ãçŸåšã®ãªããžã§ã¯ããèšè¿°ãã4ã€ã®ããããã£ã«åè§£ãããŸãã
æ¡åŒµæ©èœ
ããã¥ã¡ã³ã
ãµãŒãããŒãã£ã©ã€ãã©ãªã®ãªããžã§ã¯ãã«ç¬èªã®ã¡ãœããã远å ããããJava Collection Frameworkã«ã¡ãœããã远å ãããããããšã¯ãå€ãã®éçºè
ã«ãšã£ãŠé·å¹Žã®å€¢ã§ãã ãããŠä»ãç§ãã¡å
šå¡ã«ãã®ãããªæ©äŒããããŸãã æ¡åŒµé¢æ°ã®å®£èšã¯æ¬¡ã®ãšããã§ãã
fun AvailabilityTable.monday(from: String, to: String? = null)
éåžžã®ã¡ãœãããšã¯ç°ãªããã¡ãœããåã®åã«ã¯ã©ã¹åã远å ããŠãã©ã®ã¯ã©ã¹ãå±éãããã瀺ããŸãã ãã®äŸã§ã¯ã AvailabilityTable
ã¯Matrixã¿ã€ãã®ãšã€ãªã¢ã¹ã§ãããKotlinã®ãšã€ãªã¢ã¹ã¯ååã®å€æŽã«ãããªãããããã®ãããªå®£èšã¯ä»¥äžã®äŸã®å®£èšãšåçã§ãããå¿
ããã䟿å©ã§ã¯ãããŸããã
fun Matrix<Boolean>.monday(from: String, to: String? = null)
ããããæ®å¿µãªãããããŒã«ã䜿çšããªãããç¹å®ã®ã³ã³ããã¹ãã¯ã©ã¹ã«ã®ã¿ã¡ãœããã远å ããããšãé€ããŠãäœãã§ããŸããã ãããŠãéæ³ã¯å¿
èŠãªå Žæã«ã®ã¿çŸããŸãã ããã«ããããã®æ©èœã䜿çšããŠã€ã³ã¿ãŒãã§ãŒã¹ãæ¡åŒµããããšãã§ããŸãã è¯ãäŸã¯ã次ã®ããã«Iterableãªããžã§ã¯ããæ¡åŒµããæåã®ã¡ãœããã§ãã
fun <T> Iterable<T>.first(): T
ãã®çµæãèŠçŽ ã®ã¿ã€ãã«é¢ä¿ãªããIterableã€ã³ã¿ãŒãã§ã€ã¹ã«åºã¥ãã³ã¬ã¯ã·ã§ã³ã¯æåã®ã¡ãœãããååŸããŸãã è峿·±ãã®ã¯ãæ¡åŒµã¡ãœãããã³ã³ããã¹ãã¯ã©ã¹ã«é
眮ã§ãããããç¹å®ã®ã³ã³ããã¹ãã§ã®ã¿æ¡åŒµã¡ãœããã«ã¢ã¯ã»ã¹ã§ããããšã§ãïŒäžèšã®ã³ã³ããã¹ãã®ã©ã ããåç
§ïŒã ããã«ãNullableåã®æ¡åŒµé¢æ°ãäœæã§ããŸãïŒNullableåã®èª¬æã¯èšäºã®ç¯å²å€ã§ãããå¿
èŠã«å¿ããŠããã§èªãããšãã§ããŸãïŒã ããšãã°ãCharSequenceïŒã¿ã€ããæ¡åŒµããKotlinæšæºã©ã€ãã©ãªã®isNullOrEmpty颿°ã¯ã次ã®ããã«äœ¿çšã§ããŸãã
val s: String? = null s.isNullOrEmpty()
ãã®é¢æ°ã®ã·ã°ããã£ã¯æ¬¡ã®ãšããã§ãã
fun CharSequence?.isNullOrEmpty(): Boolean
ãã®ãããªKotlin颿°ã䜿çšããŠJavaããäœæ¥ããå Žåãæ¡åŒµé¢æ°ã¯éçãšããŠäœ¿çšã§ããŸãã
æ¿å
¥æ©èœ
ããã¥ã¡ã³ã
æ§æãçãããå¥ã®æ¹æ³ã¯ãäžçœ®é¢æ°ã䜿çšããããšã§ãã ç°¡åã«èšãã°ããã®ããŒã«ã®ãããã§ãåçŽãªç¶æ³ã§äžå¿
èŠãªã³ãŒããã€ãºãåãé€ãããšãã§ããŸããã
ã¡ã€ã³ãµã³ãã«èšäºã®assertions
ãããã¯ã¯ããã®ããŒã«ã®äœ¿ç𿹿³ã瀺ããŠããŸãã
teacherSchedule[day, lesson] shouldNotEqual null
ãã®èšèšã¯æ¬¡ãšåçã§ãã
teacherSchedule[day, lesson].shouldNotEqual(null)
ãã©ã±ãããšããããåé·ãªå ŽåããããŸãã ãã®å Žåã颿°ã«äžçœ®ä¿®é£Ÿåãå¿
èŠã§ãã
äžèšã®ã³ãŒãã§ã¯ã teacherSchedule[day, lesson]
ã³ã³ã¹ãã©ã¯ãã¯ã¹ã±ãžã¥ãŒã«ã¢ã€ãã ãè¿ãã shouldNotEqual
颿°ã¯ã¢ã€ãã ãnullã§ãªãããšã確èªããŸãã
ãã®ãããªé¢æ°ã宣èšããã«ã¯ã以äžãè¡ãå¿
èŠããããŸãã
- äžçœ®ä¿®é£Ÿåãæå®ããŸãã
- ãã©ã¡ãŒã¿ãŒã1ã€ã ãå®çŸ©ããŸãã
以äžã®ã³ãŒãã®ããã«ãæåŸã®2ã€ã®ããŒã«ãçµã¿åãããããšãã§ããŸãã
infix fun <T : Any?> T.shouldNotEqual(expected: T)
ããã©ã«ãã®ãžã§ããªãã¯åã¯ïŒNullableåéå±€ã§ã¯ãªãïŒAnyåå«ã§ããããã®ãããªå Žåã¯nullã䜿çšã§ããªããããAnyïŒåãæç€ºçã«æå®ããå¿
èŠããããŸãã
ã³ã³ããã¹ãå¶åŸ¡
ããã¥ã¡ã³ã
å€ãã®ãã¹ããããã³ã³ããã¹ãã䜿çšãããšãéåžžã«äœãã¬ãã«ã§ççºçãªæ··åç©ãçºçãããããããšãã°å¶åŸ¡ãªãã§ãæ¬¡ã®æ§æãæå³ããªããªãå ŽåããããŸãã
schedule { // SchedulingContext data { // DataContext + SchedulingContext data { } // - } }
Kotlin 1.1ããåã«ã¯ããããåé¿ããæ¹æ³ããã§ã«ãããŸããã DataContextã®ãã¹ããããã³ã³ããã¹ãã§ç¬èªã®ããŒã¿ã¡ãœãããäœæããERRORã¬ãã«ã®Deprecatedã¢ãããŒã·ã§ã³ã§ããŒã¯ããŸãã
class DataContext { @Deprecated(level = DeprecationLevel.ERROR, message = "Incorrect context") fun data(init: DataContext.() -> Unit) {} }
ãã®ã¢ãããŒãã®ãããã§ãç¡å¹ãªDSLãã«ãã®å¯èœæ§ãæé€ã§ããŸããã ãã ããSchedulingContextã®å€æ°ã®ã¡ãœããã§ã¯ãäžå®éã®ã«ãŒãã³äœæ¥ãè¡ããããããã³ã³ããã¹ããå¶åŸ¡ãããã¹ãŠã®æ¬²æ±ãæããããŸããã
Kotlin 1.1ã¯ãæ°ããå¶åŸ¡ããŒã«-@DslMarkerã¢ãããŒã·ã§ã³ãå°å
¥ããŸãã ããã¯ãç¬èªã®æ³šéã«é©çšãããŸããæ³šéã¯ãã³ã³ããã¹ããããŒã¯ããããã«å¿
èŠã§ãã æ³šéãäœæããŸããããæ³šéã¯ãæŠåšåº«ã«ããæ°ããããŒã«ã䜿çšããŠããŒã¯ããŸãã
@DslMarker annotation class MyCustomDslMarker
次ã«ãã³ã³ããã¹ãã«ã©ãã«ãä»ããå¿
èŠããããŸãã äž»ãªäŸã§ã¯ããããã¯SchedulingContextãšDataContextã§ãã åã¯ã©ã¹ãåäžã®DSLããŒã«ãŒã§ããŒã¯ãããšããäºå®ã«ãããæ¬¡ã®ããšãèµ·ãããŸãã
@MyCustomDslMarker class SchedulingContext { ... } @MyCustomDslMarker class DataContext { ... } fun demo() { schedule {
å€ãã®æéãšåŽåãåæžãããã®ãããªã¢ãããŒãã®ãã¹ãŠã®åã³ã«ããããããã1ã€ã®åé¡ãæ®ã£ãŠããŸãã ã¡ã€ã³ã®äŸã«æ³šç®ãããšã次ã®ã³ãŒãã衚瀺ãããŸãã
schedule { data { student { name = "Petrov" } ... } }
Student, , , , , @MyCustomDslMarker , , , .
Student data {}
, .. DataContext , :
schedule { data { student { student { } } } }
, , . :
- , , StudentContext. @DslMarker.
- , , IStudent ( ), -, , , .
@MyCustomDslMarker class StudentContext(val owner: Student = Student()): IStudent by owner
- @Deprecated, . , , , .
deprecated extension Identifiable .
@Deprecated("Incorrect context", level = DeprecationLevel.ERROR) fun Identifiable.student(init: () -> Unit) {}
, , DSL .
DSL
DSL Kotlin , DSL .
DSL
, DSL, . DSL extension , .
, , : " callback'", DSL, . , , . , DSL , .
This, it!?
this it DSL. - it, , , , . , .
, . " " DSL. , , , val mainContext = this
. . , , , " ", . , DSL, , , DSL , - . DSL (, ), , .. .
, ?
- DSL, : " ?". . DSL, , . , . , .. - : " , ?" , , .
ãããã«
, - . , .
, - , , . , DSL . , , .
" ", , DSL , , , , .
- !