Kotlin funcional. Em nome da bondade, arco-íris e tudo isso

Introdução

O próprio Kotlin é uma ferramenta muito poderosa, mas muitas vezes não o usa em sua capacidade total, transformando-o em algum tipo de ... Java 6. Vou tentar dizer por que você não deve fazer isso e como usar as características funcionais da linguagem ao máximo.





Funções de ordem superior

Vou começar com eles. E, ao mesmo tempo, direi do que se trata: quando uma função recebe outra função como parâmetro ou a retorna, é uma função de ordem superior. Simples, não é? Mas como você usa isso?





O fato de que funções no Kotlin podem receber e retornar outras funções para nós deve significar que podemos escrevê-las em uma variável. Vai parecer algo assim:





val foo: () -> Unit = {  }
      
      



Então, podemos passá-lo usando uma sintaxe como:





run(foo)
      
      



Ótimo, mas e se quisermos usar uma função que definimos da maneira normal? Ou então passar um método? Bem, também existe uma possibilidade - um link para uma função . É assim que podemos verificar se uma string está vazia:





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)
      
      



Nesse caso, tenho duas novidades - a primeira é que seus gostos são muito específicos, e a segunda é que, neste caso, nossa função de extensão é processada como a função mais comum, em que o primeiro parâmetro é uma instância da classe que se estende.








All Articles