Tìm hiểu về kotlin DSL

I, DSL là gì

A domain-specific language (DSL) is a computer language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains

  • Đói với các developer, DSL cung cấp các tool để đơn giản hoá việc thực hiện các cấu trúc phức tạp bằng cách tận dụng các tool sẵn có của ngôn ngữ lập trình.
  • Trong Kotlin, chúng ta cũng đã sử dụng rất nhiều kotlin DSL. Hàm forEach() cũng là 1 Kotlin DSL:
1
2
3
listOf(1, 2, 3).forEach {
//...
}

II, Kotlin DSL

  • Trước khi tìm hiểu về Kotlin DSL, bạn nên biết trước về high-order functionfunction literal với receiver. Nếu bạn đã sẵn sàng thì chúng ta bắt đầu tìm hiểu về kotlin DSL

1, Tạo Kotlin DSL

  • Để hiểu rõ hơn, chúng ta sẽ đi xem xét ví dụ sau:
1
2
3
4
5
6
7
8
9
fun getResult(a: Int, b: Int, action: Int.(Int) -> Int): Int {
return action(a, b)
}

fun main(){
val text = getResult(1, 2){
this + it
} // Result: 3
}
  • Function getResult() có 3 parameter, trong đó action có kiểu là function type với receiver. Do đó action cần được khởi tạo bởi function literal với receiver như ở main().
  • Trên đây là ví dụ để xây dựng nên Kotlin DSL.
  • Kotlin xây dựng sẵn cho chúng ta một số library sử dụng Kotlin DSL:
    • Tạo ra markup code như HTML, XML.
    • Làm việc với UI component: Anko.
    • Cấu hình route cho web server: Ktor

2, Sử dụng infix keyword

  • Chúng ta có thể thêm infix keyword cho function.

  • Khi đó tên của function được gọi là infix notation, chúng ta có thể gọi function sử dụng infix notion (bỏ qua .()).

  • Các infix function cần tuân thủ:

    • Chúng phải là member function hoặc extension function.
    • Chúng chỉ có 1 paramter không có default value (vararg không được chấp nhận ).
  • Ví dụ 1: sử dụng infix với extension function

1
2
3
4
5
infix fun Int.plus(other: Int): Int = this + other

1 plus 2 // ok
1.plus(2) // ok
plus(1, 2) // ok
  • Ví dụ 2: sử dụng infix với member function, khi sử dụng infix notation bắt buộc phải có this keyword.
1
2
3
4
5
6
7
8
9
class MyStringCollection {
infix fun add(s: String) { /*...*/ }

fun build() {
this add "abc" // Correct
add("abc") // Correct
//add "abc" // Incorrect: the receiver must be specified
}
}