Kotlin fonctionnel. Au nom de la bonté, arc-en-ciel et tout ça

introduction

Kotlin lui-même est un outil très puissant, mais souvent ne l'utilisent pas à sa pleine capacité, le transformant en une sorte de ... Java 6. Je vais essayer de vous dire pourquoi vous ne devriez pas faire cela et comment l'utiliser les caractéristiques fonctionnelles de la langue au maximum.





Fonctions d'ordre supérieur

Je vais commencer par eux. Et, en même temps, je vais vous dire de quoi il s'agit: lorsqu'une fonction prend une autre fonction comme paramètre ou la renvoie, c'est une fonction d'ordre supérieur. C'est simple, n'est-ce pas? Mais comment l'utilisez-vous?





Le fait que les fonctions de Kotlin puissent recevoir et renvoyer d'autres fonctions pour nous devrait signifier que nous pouvons les écrire dans une variable. Cela ressemblera à quelque chose comme ceci:





val foo: () -> Unit = {  }
      
      



Ensuite, nous pouvons le transmettre en utilisant une syntaxe comme:





run(foo)
      
      



Génial, mais que faire si nous voulons utiliser une fonction que nous avons définie de manière normale? Ou passer une méthode du tout? Eh bien, il y a une possibilité pour cela aussi - un lien vers une fonction . Voici comment nous pouvons vérifier la vacuité d'une chaîne:





str.run(String::isEmpty)
      
      



. , , . , . ? ? "" ?



, , , , - :





val parse: (String) -> List<Int> = { it.split(":").map(String::toInt) }

val (xMin, yMin) = parse(data["from"])
val (xMax, yMax) = parse(data["to"])
      
      



, , , , , .  let



run



with



apply



,  also



. ? , .





inline fun <T, R> T.let(block: (T) -> R): R
inline fun <T> T.also(block: (T) -> Unit): T
      
      



let



also



. , - block(this)



. , " " . , . also



, let



, .





inline fun <R> run(block: () -> R): R
inline fun <T, R> T.run(block: T.() -> R): R
inline fun <T, R> with(receiver: T, block: T.() -> R): R
inline fun <T> T.apply(block: T.() -> Unit): T
      
      



run



, with



apply



:

run



let



, apply also



, with



run



, receiver



. , let



also



? , it



this



, .



? .



, , , , , , . "" .





inline



? , , . , , , , .



. .





, , - ( )?



, , :





let {
  val some = Some()
  it.run(some::doSome)
}
      
      



:





let(Some::doSome)
      
      



, , ?





, , ? , . , companion object



:





class Some {
  companion object {
    fun doSome(any: Any) = run {}
  }
}
      
      



, .





Factory

:





val other = Other()
val stuff = other.produceStuff()

val some = Some(stuff)
      
      



. , Other Some, .





, :





val some = Some(
  Other().produceStuff()
)
      
      



. , , ... ? , Factory-:





class Some {
  companion object Factory {
    inline fun <T>create(t: T?, f: (T?) -> Stuff) = Some(f(t))
  }
}
      
      



:





val some = Some(Other()) { it.doStuff() }
      
      



Other :





val some = Some.create(Other) { it.create().doStuff() }
      
      



, . ? , . , .





-

, - , . , , . :





fun Some.foo() = run { }
      
      



:





val foo: Some.() -> Unit = {  }
      
      



, - . -. , IntelliJ IDEA , - , .





, -. val



, foo



, . fun



, , .





:





class Some {
  fun Other.someExtention() = run { }
}
      
      



, , "", - .





, . . . , , - Some Other.





, , , - Some::someExtention



. , - .





P.S.

, , . , KFunction.





fun Some.overlay(f: KFunction1<Some, Any>) = f(this)
      
      



Dans ce cas, j'ai deux nouvelles - la première est que vos goûts sont très spécifiques, et la seconde est que dans ce cas, notre fonction d'extension est traitée comme la fonction la plus ordinaire, dans laquelle le premier paramètre est une instance de la classe qu'il s'étend.








All Articles