// Define a class named "Person"
class Person(val name: String) {
// Define an infix member function "isFriendWith"
infix fun isFriendWith(anotherPerson: Person): Boolean {
// Just a simple example: two persons are friends if their names have the same length
return this.name.length == anotherPerson.name.length
}
}
// Define an infix extension function "hasSameLengthAs" for the String class
infix fun String.hasSameLengthAs(anotherString: String): Boolean {
return this.length == anotherString.length
}
fun main() {
val alice = Person("Alice")
val bob = Person("Bob")
val carol = Person("Carol")
// Use the infix function "isFriendWith"
val aliceAndBobAreFriends = alice isFriendWith bob
val aliceAndCarolAreFriends = alice isFriendWith carol
println("Alice and Bob are friends: $aliceAndBobAreFriends") // true
println("Alice and Carol are friends: $aliceAndCarolAreFriends") // false
// Use the infix extension function "hasSameLengthAs"
val stringsHaveSameLength = "Kotlin" hasSameLengthAs "Python"
println("Kotlin and Python have the same length: $stringsHaveSameLength") // true
}
독립적인 외부 DSL과는 다르게 범용언어로 작성된 프로그램 일부인 내부 DSL
// 이런식으로 sql문을 내부 DSL 로 작성 가능 결과가 네이티브 코틀린 객체 .
(Country join Customer)
.slice(Country.name, Count(Customer.id))
.selectAll()
.groupBy(Country.name)
.orderBy(Count(Customer.id), isAsc = false)
.limit(1)
```
## DSL 구조
람다 중첩이나 메소드 연쇄시키는 방식으로 구조를 만듬 .
여러 함수를 호출
코틀린으로 HTML 만들면 ?
타입 안정성 보장 , Td는 tr안에서만 작성 해야 되!
fun createAnotherTable() = createHTML().table {
val numbers = mapOf(1 to "one", 2 to "two")
for ((num, string) in numbers) {
tr {
td { +"$num" }
td { +string }
}
}
}
open class Tag
class TABLE : Tag() {
fun tr(init: TR.() -> Unit) {
// Implementation
}
}
class TR : Tag() {
fun td(init: TD.() -> Unit) {
// Implementation
}
}
class TD : Tag()
open class Tag(val name: String) {
private val children = mutableListOf<Tag>()
protected fun <T : Tag> doInit(child: T, init: T.() -> Unit) {
child.init()
children.add(child)
}
override fun toString() = "<$name>${children.joinToString("")}</$name>"
}
fun table(init: TABLE.() -> Unit) = TABLE().apply(init)
class TABLE : Tag("table") {
fun tr(init: TR.() -> Unit) = doInit(TR(), init)
}
class TR : Tag("tr") {
fun td(init: TD.() -> Unit) = doInit(TD(), init)
}
class TD : Tag("td")
fun createTable() = table {
tr {
td { }
}
}
fun main() {
println(createTable())
}
fun dropdownExample() = createHTML().dropdown {
dropdownButton { +"Dropdown" }
dropdownMenu(
item("#", "Action"),
item("#", "Another action"),
divider(),
dropdownHeader("Header"),
item("#", "Separated link")
)
}
기존 HTML 에서 불필요한 세부사항을 제거하고 함수로 감춰둠.
객체를 함수처럼 호출해보자
class Greeter(val greeting: String) {
operator fun invoke(name: String) {
println("$greeting, $name!")
}
}
val bavarianGreeter = Greeter("Servus")
bavarianGreeter("Dmitry") // Output: Servus, Dmitry!
함수 앞에 operator 변경자를 붙은 Invoke 메서드를 객체를 함수처럼 호출가능
Invoke 관례와 함수 타입
// Define a simple lambda
val lambda = { x: Int, y: Int -> x + y }
// Call the lambda as if it were a function
val sum = lambda(3, 4)
println("Sum of 3 and 4 is: $sum") // Output: Sum of 3 and 4 is: 7
// Define a custom class with an 'invoke' operator function
class Multiplier(val factor: Int) {
operator fun invoke(x: Int): Int {
return x * factor
}
}
// Create an instance of the custom class
val triple = Multiplier(3)
// Call the instance as if it were a function
val result = triple(5)
println("Triple of 5 is: $result") // Output: Triple of 5 is: 15
data class Issue(
val id: String,
val project: String,
val type: String,
val priority: String,
val description: String
)
class ImportantIssuesPredicate(val project: String) : (Issue) -> Boolean {
override fun invoke(issue: Issue): Boolean {
return issue.project == project && issue.isImportant()
}
private fun Issue.isImportant(): Boolean {
return type == "Bug" && (priority == "Major" || priority == "Critical")
}
}
val i1 = Issue(
"IDEA-154446",
"IDEA",
"Bug",
"Major",
"Save settings failed"
)
val i2 = Issue(
"KT-12183",
"Kotlin",
"Feature",
"Normal",
"Intention: convert several calls on the same receiver to with/apply"
)
val predicate = ImportantIssuesPredicate("IDEA")
for (issue in listOf(i1, i2).filter(predicate)) {
println(issue.id)
}
```
data class Person(val name: String, val age: Int)
class AgeFilter(val minAge: Int, val maxAge: Int) : (Person) -> Boolean {
override fun invoke(person: Person): Boolean {
return person.isWithinAgeRange()
}
private fun Person.isWithinAgeRange(): Boolean {
return age in minAge..maxAge
}
}
fun main() {
val people = listOf(
Person("Alice", 30),
Person("Bob", 25),
Person("Charlie", 40),
Person("David", 20)
)
val ageFilter = AgeFilter(25, 35)
val filteredPeople = people.filter(ageFilter)
println(filteredPeople)
}
dependencies {
compile("junit:junit:4.11")
}
class DependencyHandler {
fun compile(coordinate: String) {
println("Added dependency on $coordinate")
}
operator fun invoke(body: DependencyHandler.() -> Unit) {
body()
}
}
val dependencies = DependencyHandler()
dependencies.compile("org.jetbrains.kotlin:kotlin-stdlib:1.0.0") // Output: Added dependency on org.jetbrains.kotlin:kotlin-stdlib:1.0.0
dependencies {
compile("org.jetbrains.kotlin:kotlin-reflect:1.0.0")
} // Output: Added dependency on org.jetbrains.kotlin:kotlin-reflect:1.0.0
complie함수도 사용가능하고 , 여러개의 람다 인자를 넘겨주는것을 가능하게하는 구현
두번째 코드는 결과?
dependencies.invoke {
this.compile("org.jetbrains.kotlin:kotlin-reflect:1.0.0")
}
s should startwith(“kot”)
infix fun T.should(matcher: Matcher) = matcher.test(this)
interface Matcher<T> {
fun test(value: T)
}
class StartWith(val prefix: String) : Matcher<String> {
override fun test(value: String) {
if (!value.startsWith(prefix)) {
throw AssertionError("String $value does not start with $prefix")
}
}
}
이런식으로 구현가능한게 신기하다. 좀더 익숙해지게 공부를 하면 뭔가 더 좋은 코드를 짤 수 잇을거같다
아직까지 100퍼 완전 내것이 된건아니지만 코드를 보니 저렇게도 짤수잇구나 신기하다
// "kotlin”. should(start).with("kot")
object Start
infix fun String.should(x: Start): StartWrapper = StartWrapper(this)
class StartWrapper(val value: String) {
infix fun with(prefix: String) {
if (!value.startsWith(prefix)) {
throw AssertionError("String does not start with $prefix: $value")
} else {
Unit
}
}
}
이런식으로 중위연산자를 활용하면 테스트 코드를 좀더 명확히? 짤 수 있게된다.
한번 이런식으로 짜두는 것도 좋을듯.. 연습하자