Kotlin DSL
~ ~
11/2 2 Android
Kamedon
•
• Kotlin
•
•
• DSL
• DSL
• DSL
•
DSL
DSL
• domain-specific language/ )
• DSL
(wikipedia )
• 

• DSL 

Builder
//Java
Human human= new Human.Builder()
.setName("Kamedon")
.setAge(30)
.build();
//Kotlin
class Human(val name: String, val age: Int)
Human(age = 30, name = "Kamedon")
if(human.isAdult()){
//成人だったらなにかする
}
Build DSL
buildscript {
ext.kotlin_version = '1.2.70'
repositories {
google()
jcenter()
maven {
url 'http://kamedon.github.com/Validation/repository'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:
$kotlin_version"
}
}
•
Layout Anko)
verticalLayout {
val name = editText()
button("Say Hello") {
onClick { toast("Hello, ${name.text}!") }
}
}
•
• LinearLayout
DI DSL(Kodein)
Kodein {
bind<Presenter>() with singleton {
Presenter(instance(), inetance())
}
}
val presenter: Presenter by instance()
•
•
DSL
•
•
• IDE
• Sansan Kotlin DSL
DSL
•
•
• Kotlin 

Java DSL
• DSL Kotlin
DSL
• Validation DSL
• DSL
• Validation 

https://github.com/kamedon/Validation
• 

• 

[ ]

5 10 

[ ]

20
• 

•
•
•
•
DSL
DSL (1)
•
• 5
•
• X be Y
DSL (2)
•
• 5 

• X be Y 

not
• X be Y not Message
DSL
be not
be not
be not
be not
be not
DSL
be not
be not
be not
be not
be not
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
•
DSL
• : operator invoke
• {} : lambda lambda
• ()
• : (Extensions Functions or
Properties)
• : infix)
• var val : Builder
be
be not
be not
DSL
be not
be not
be not
be not
be not
be not
be not
be not
be not
operator invoke + lambda
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
}
•
class Validation<T> {
companion object {
operator fun <T>
invoke(init: Validation<T>.() -> Unit): Validation<T> {
return Validation<T>().apply(init)
}
}
}
+ lambda
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
}
•
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(
init: ChildValidation<T>.() -> Unit
) {
validations.put(this, ChildValidation<T>().apply(init))
}
}
infix( )
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
}
•
class ChildValidation<T> {
fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(message: String)
}
DSL
Validation<User> {
"name"{
}
}
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(init: ChildValidation<T>.() -> Unit) {
validations.put(this, ChildValidation<T>().apply(init))
}
companion object {
inline operator fun <T> invoke(
init: Validation<T>.() -> Unit): Validation<T> {
return Validation<T>().apply(init)
}
}
}
DSL
be { name.isNotBlank() } not "入力してください"
class ChildValidation<T> {
val validations = mutableListOf<Pair<T.() -> Boolean, String>>()
infix fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(message: String) {
validations.add(Pair(this, message))
}
}
•
DSL
Validation<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
•
validate
Validate
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
fun validate(value: T): Map<String, List<String>> {
val messages = mutableMapOf<String, List<String>>()
validations.forEach { map ->
val errors = map.value.validations.asSequence()
.filter { !it.first.invoke(value) }
.map { it.second }
.filter { it.isNotEmpty() }
.toList()
if(errors.isNotEmpty()){
messages.put(map.key, errors)
}
}
return messages
}
}
DSL Builder
class Validation<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(init: ChildValidation<T>.() -> Unit) {
validations.put(this, ChildValidation<T>().apply(init))
}
companion object {
inline operator fun <T> invoke(
init: Validation<T>.() -> Unit): Validation<T> {
return Validation<T>().apply(init)
}
}
fun validate(value: T): Map<String, List<String>>
}
DSL Builder
class ValidationBuilder<T> {
val validations = mutableMapOf<String, ChildValidation<T>>()
operator fun String.invoke(init: ChildValidation<T>.() -> Unit) {
validations.put(this, ChildValidation<T>().apply(init))
}
fun build(): Validation<T> {
return Validation(validations)
}
}
class Validation<T>(val validations: Map<String, ChildValidation<T>>) {
companion object {
inline operator fun <T> invoke(
init: ValidationBuilder<T>.() -> Unit): Validation<T> {
val builder = ValidationBuilder<T>().apply(init)
return builder.build()
}
}
}
DSL
DSL
•
•
•
• 

• DSL inline
0
inline
class Sample {
fun run(f: () -> Unit) {
f()
}
inline fun inlineRun(f: () -> Unit) {
f()
}
fun main() {
run { print("run") }
inlineRun { print("inlineRun") }
}
}
public final class Sample {
public final void run(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void inlineRun(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void main() {
this.run((Function0)null.INSTANCE);
String var2 = "inlineRun";
System.out.print(var2);
}
}
Inline
public final class Sample {
public final void run(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void inlineRun(@NotNull Function0 f) {
Intrinsics.checkParameterIsNotNull(f, "f");
f.invoke();
}
public final void main() {
this.run((Function0)null.INSTANCE);
String var2 = "inlineRun";
System.out.print(var2);
}
}
• X be Y not error_message
• not
• not 

error message
• be 20 

not error message “20 ”
Validation<User> {
"name"{
be { name.length >= 5 } not "5文字以下"
be { name.length <= 10 } not "10文字以下"
}
"age"{
be { age >= 20 } not error message "20歳以上"
}
}
•
fun be(f: T.() -> Boolean) = f
infix fun (T.() -> Boolean).not(???) : ???
be { age >= 20 } not error message "20歳以上"
• error message 

•
Syntax object
object error
infix fun (T.() -> Boolean).not(syntax: error) = this
infix fun (T.() -> Boolean).message(message: String) {
validations.add(Pair(this, message))
}
be { age >= 20 } not error message "20歳以上"
• object error this
• not message
Syntax object
object error
infix fun (T.() -> Boolean).not(syntax: error) = this
infix fun (T.() -> Boolean).message(message: String) {
validations.add(Pair(this, message))
}
be { age >= 20 } not error message “20歳以上"
• object error this
• not message
IDE
be { age >= 0 } not error not error not error …
•
• not error
•
•
• not error message
IDE
class ErrorMessageSyntax<T>(val validation: T.() -> Boolean)
infix fun (T.() -> Boolean).not(syntax: error) =
ErrorMessageSyntax(this)
infix fun ErrorMessageSyntax<T>.message(message: String) {
validations.add(Pair(this.validation, message))
}
•
•
•
IDE
be { age >= 0 } not error
•
•
be { age >= 20 } not with callback "20歳以上入力"{
print("debug log")
}
class WithCallbackSyntax<T>(val validation: T.() -> Boolean)
infix fun (T.() -> Boolean).not(syntax: with) =
WithCallbackSyntax(this)
•
• error with 

•
• GitHub
•
•
•
• User Todo
• 

DSL
• User 5 …
• Todo …
•
• Validations { define<T> } 

DSL
define
define
Validations {
define<User> {
"name"{
be { name.isNotBlank() } not "入力してください"
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
define
define
Validations {
}
object Validations {
val map = mutableMapOf<String, Any>()
operator fun invoke(init: Validations.() -> Unit) {
init()
}
}
define Validation<T>
Validations {
define<User> {
}
}
object Validations {
inline fun <reified T>
define(init: ValidationBuilder<T>.() -> Unit) {
val validation = ValidationBuilder<T>().apply(init).build()
val key = (T::class.java).run {
"${`package`.name}.$simpleName"
}
map[key] = validation
}
}
Validations {
define<User> {
"name"{
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
//{name=[5文字以上入力], age=[20歳以上で入力]}
Validations.validate(User("k",1).validate())
//{body=[入力してください]}
Validations.validate(Todo("").validate())
•
•
•
•
•
inline fun <reified T> T.validate() = 

Validations.validate(this)
•
•
Validations {
define<User> {
"name"{
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
//{name=[5文字以上入力], age=[20歳以上で入力]}
User("k",1).validate()
//{body=[入力してください]}
Todo("").validate()
• 

• validate
• define
• interface
• interface
interface Validable
inline fun <reified T : Validable> T.validate()
= Validations.validate(this)
• Validable
validate
• validate
class User(val name: String, val age: Int) : Validable
class Todo(val body: String) : Validable
Validations {
define<User> {
"name"{
be { name.length >= 5 } not "5文字以上入力"
be { name.length <= 10 } not "10文字以下で入力"
}
"age"{
be { age >= 0 } not "入力してください"
be { age >= 20 } not "20歳以上で入力"
}
}
define<Todo> {
"body"{
be { body.isNotBlank() } not "入力してください"
}
}
}
User("k",1).validate()
Todo("").validate()
interface Validable<T> {
val key: String
fun validate(): Map<String, List<String>> =
(Validations.get(key) as Validation<T>).validate(this as T)
}
}
inline fun <reified T> Validable<T>.key() = 

Validations.key<T>()
class User(val name: String, val age: Int) : Validable<User> {
override val key: String = key()
}
User("k", 3).validate()
/
•
• 

get,setter
(Delegated Properties)
class Delegate : ReadWriteProperty<Hoge, String> {
var value = ""
override fun getValue(thisRef: Hoge, property: KProperty<*>): String {
return "value:" + value
}
override fun setValue(thisRef: Hoge, property: KProperty<*>, value: String) {
this.value = value
}
}
class Hoge {
var x by Delegate()
}
fun main() {
val hoge = Hoge()
hoge.x = "test"
print(hoge.x) // value: test
}
(Delegated Properties)
object ValidableDelegate {
class Validable<T>(private val key: String)
: ReadOnlyProperty<Any, Validation<T>> {
override fun getValue(thisRef: Any, property: KProperty<*>)
: Validation<T> {
return Validations.get(key) as Validation<T>
}
}
inline fun <reified T> get() = Validable<T>(Validations.key<T>())
}
class Todo(val body: String) {
private val validation by ValidableDelegate.get<Todo>()
fun validate() = validation.validate(this)
}
Todo("").validate()
• inline
• syntax object
• Interface
• interface
• /
つくってあそぼ Kotlin DSL ~拡張編~

つくってあそぼ Kotlin DSL ~拡張編~

  • 1.
    Kotlin DSL ~ ~ 11/22 Android Kamedon
  • 2.
  • 3.
  • 4.
  • 5.
    DSL • domain-specific language/) • DSL (wikipedia ) • 

  • 6.
  • 7.
    Builder //Java Human human= newHuman.Builder() .setName("Kamedon") .setAge(30) .build(); //Kotlin class Human(val name: String, val age: Int) Human(age = 30, name = "Kamedon") if(human.isAdult()){ //成人だったらなにかする }
  • 8.
    Build DSL buildscript { ext.kotlin_version= '1.2.70' repositories { google() jcenter() maven { url 'http://kamedon.github.com/Validation/repository' } } dependencies { classpath 'com.android.tools.build:gradle:3.1.4' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin: $kotlin_version" } } •
  • 9.
    Layout Anko) verticalLayout { valname = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } } • • LinearLayout
  • 10.
    DI DSL(Kodein) Kodein { bind<Presenter>()with singleton { Presenter(instance(), inetance()) } } val presenter: Presenter by instance() • •
  • 11.
  • 12.
  • 13.
  • 14.
    • Validation DSL •DSL • Validation 
 https://github.com/kamedon/Validation
  • 16.
    • 
 • 
 []
 5 10 
 [ ]
 20 • 

  • 18.
  • 19.
  • 20.
  • 21.
    DSL (2) • • 5
 • X be Y 
 not • X be Y not Message
  • 22.
    DSL be not be not benot be not be not
  • 23.
    DSL be not be not benot be not be not
  • 24.
    Validation<User> { "name"{ be {name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } •
  • 25.
  • 26.
    • : operatorinvoke • {} : lambda lambda • () • : (Extensions Functions or Properties) • : infix) • var val : Builder
  • 27.
  • 28.
    DSL be not be not benot be not be not
  • 29.
    be not be not benot be not
  • 30.
    operator invoke +lambda Validation<User> { "name"{ be { name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } } • class Validation<T> { companion object { operator fun <T> invoke(init: Validation<T>.() -> Unit): Validation<T> { return Validation<T>().apply(init) } } }
  • 31.
    + lambda Validation<User> { "name"{ be{ name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } } • class Validation<T> { val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke( init: ChildValidation<T>.() -> Unit ) { validations.put(this, ChildValidation<T>().apply(init)) } }
  • 32.
    infix( ) Validation<User> { "name"{ be{ name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } } • class ChildValidation<T> { fun be(f: T.() -> Boolean) = f infix fun (T.() -> Boolean).not(message: String) }
  • 33.
    DSL Validation<User> { "name"{ } } class Validation<T>{ val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke(init: ChildValidation<T>.() -> Unit) { validations.put(this, ChildValidation<T>().apply(init)) } companion object { inline operator fun <T> invoke( init: Validation<T>.() -> Unit): Validation<T> { return Validation<T>().apply(init) } } }
  • 34.
    DSL be { name.isNotBlank()} not "入力してください" class ChildValidation<T> { val validations = mutableListOf<Pair<T.() -> Boolean, String>>() infix fun be(f: T.() -> Boolean) = f infix fun (T.() -> Boolean).not(message: String) { validations.add(Pair(this, message)) } } •
  • 35.
    DSL Validation<User> { "name"{ be {name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } • validate
  • 36.
    Validate class Validation<T> { valvalidations = mutableMapOf<String, ChildValidation<T>>() fun validate(value: T): Map<String, List<String>> { val messages = mutableMapOf<String, List<String>>() validations.forEach { map -> val errors = map.value.validations.asSequence() .filter { !it.first.invoke(value) } .map { it.second } .filter { it.isNotEmpty() } .toList() if(errors.isNotEmpty()){ messages.put(map.key, errors) } } return messages } }
  • 37.
    DSL Builder class Validation<T>{ val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke(init: ChildValidation<T>.() -> Unit) { validations.put(this, ChildValidation<T>().apply(init)) } companion object { inline operator fun <T> invoke( init: Validation<T>.() -> Unit): Validation<T> { return Validation<T>().apply(init) } } fun validate(value: T): Map<String, List<String>> }
  • 38.
    DSL Builder class ValidationBuilder<T>{ val validations = mutableMapOf<String, ChildValidation<T>>() operator fun String.invoke(init: ChildValidation<T>.() -> Unit) { validations.put(this, ChildValidation<T>().apply(init)) } fun build(): Validation<T> { return Validation(validations) } } class Validation<T>(val validations: Map<String, ChildValidation<T>>) { companion object { inline operator fun <T> invoke( init: ValidationBuilder<T>.() -> Unit): Validation<T> { val builder = ValidationBuilder<T>().apply(init) return builder.build() } } }
  • 39.
  • 40.
  • 42.
  • 43.
    inline class Sample { funrun(f: () -> Unit) { f() } inline fun inlineRun(f: () -> Unit) { f() } fun main() { run { print("run") } inlineRun { print("inlineRun") } } }
  • 44.
    public final classSample { public final void run(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void inlineRun(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void main() { this.run((Function0)null.INSTANCE); String var2 = "inlineRun"; System.out.print(var2); } }
  • 45.
    Inline public final classSample { public final void run(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void inlineRun(@NotNull Function0 f) { Intrinsics.checkParameterIsNotNull(f, "f"); f.invoke(); } public final void main() { this.run((Function0)null.INSTANCE); String var2 = "inlineRun"; System.out.print(var2); } }
  • 47.
    • X beY not error_message • not • not 
 error message • be 20 
 not error message “20 ”
  • 48.
    Validation<User> { "name"{ be {name.length >= 5 } not "5文字以下" be { name.length <= 10 } not "10文字以下" } "age"{ be { age >= 20 } not error message "20歳以上" } } •
  • 49.
    fun be(f: T.()-> Boolean) = f infix fun (T.() -> Boolean).not(???) : ??? be { age >= 20 } not error message "20歳以上" • error message 
 •
  • 50.
    Syntax object object error infixfun (T.() -> Boolean).not(syntax: error) = this infix fun (T.() -> Boolean).message(message: String) { validations.add(Pair(this, message)) } be { age >= 20 } not error message "20歳以上" • object error this • not message
  • 51.
    Syntax object object error infixfun (T.() -> Boolean).not(syntax: error) = this infix fun (T.() -> Boolean).message(message: String) { validations.add(Pair(this, message)) } be { age >= 20 } not error message “20歳以上" • object error this • not message
  • 52.
    IDE be { age>= 0 } not error not error not error … • • not error • • • not error message
  • 53.
    IDE class ErrorMessageSyntax<T>(val validation:T.() -> Boolean) infix fun (T.() -> Boolean).not(syntax: error) = ErrorMessageSyntax(this) infix fun ErrorMessageSyntax<T>.message(message: String) { validations.add(Pair(this.validation, message)) } • • •
  • 54.
    IDE be { age>= 0 } not error • •
  • 55.
    be { age>= 20 } not with callback "20歳以上入力"{ print("debug log") } class WithCallbackSyntax<T>(val validation: T.() -> Boolean) infix fun (T.() -> Boolean).not(syntax: with) = WithCallbackSyntax(this) • • error with 
 • • GitHub
  • 56.
  • 58.
  • 60.
    DSL • User 5… • Todo … • • Validations { define<T> } 
 DSL
  • 61.
  • 62.
    Validations { define<User> { "name"{ be{ name.isNotBlank() } not "入力してください" be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } }
  • 63.
  • 64.
    Validations { } object Validations{ val map = mutableMapOf<String, Any>() operator fun invoke(init: Validations.() -> Unit) { init() } }
  • 65.
    define Validation<T> Validations { define<User>{ } } object Validations { inline fun <reified T> define(init: ValidationBuilder<T>.() -> Unit) { val validation = ValidationBuilder<T>().apply(init).build() val key = (T::class.java).run { "${`package`.name}.$simpleName" } map[key] = validation } }
  • 66.
    Validations { define<User> { "name"{ be{ name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } } //{name=[5文字以上入力], age=[20歳以上で入力]} Validations.validate(User("k",1).validate()) //{body=[入力してください]} Validations.validate(Todo("").validate())
  • 68.
  • 69.
    inline fun <reifiedT> T.validate() = 
 Validations.validate(this) • •
  • 70.
    Validations { define<User> { "name"{ be{ name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } } //{name=[5文字以上入力], age=[20歳以上で入力]} User("k",1).validate() //{body=[入力してください]} Todo("").validate()
  • 71.
  • 72.
  • 73.
    interface Validable inline fun<reified T : Validable> T.validate() = Validations.validate(this) • Validable validate • validate
  • 74.
    class User(val name:String, val age: Int) : Validable class Todo(val body: String) : Validable Validations { define<User> { "name"{ be { name.length >= 5 } not "5文字以上入力" be { name.length <= 10 } not "10文字以下で入力" } "age"{ be { age >= 0 } not "入力してください" be { age >= 20 } not "20歳以上で入力" } } define<Todo> { "body"{ be { body.isNotBlank() } not "入力してください" } } } User("k",1).validate() Todo("").validate()
  • 75.
    interface Validable<T> { valkey: String fun validate(): Map<String, List<String>> = (Validations.get(key) as Validation<T>).validate(this as T) } } inline fun <reified T> Validable<T>.key() = 
 Validations.key<T>() class User(val name: String, val age: Int) : Validable<User> { override val key: String = key() } User("k", 3).validate()
  • 76.
  • 77.
    (Delegated Properties) class Delegate: ReadWriteProperty<Hoge, String> { var value = "" override fun getValue(thisRef: Hoge, property: KProperty<*>): String { return "value:" + value } override fun setValue(thisRef: Hoge, property: KProperty<*>, value: String) { this.value = value } } class Hoge { var x by Delegate() } fun main() { val hoge = Hoge() hoge.x = "test" print(hoge.x) // value: test }
  • 78.
    (Delegated Properties) object ValidableDelegate{ class Validable<T>(private val key: String) : ReadOnlyProperty<Any, Validation<T>> { override fun getValue(thisRef: Any, property: KProperty<*>) : Validation<T> { return Validations.get(key) as Validation<T> } } inline fun <reified T> get() = Validable<T>(Validations.key<T>()) } class Todo(val body: String) { private val validation by ValidableDelegate.get<Todo>() fun validate() = validation.validate(this) } Todo("").validate()
  • 79.
    • inline • syntaxobject • Interface • interface • /