Kotlin
funzioni
Ricerca…
Sintassi
- fun Name ( Params ) = ...
- nome divertente ( Params ) {...}
- Fun Name ( Params ): Digitare {...}
- divertente < Tipo argomento > Nome ( Params ): Tipo {...}
- Inline divertimento Nome (Parametri): Type {...}
- { ArgName : ArgType -> ...}
- { ArgName -> ...}
- { ArgNames -> ...}
- {( ArgName : ArgType ): Type -> ...}
Parametri
Parametro | Dettagli |
---|---|
Nome | Nome della funzione |
Parametri | Valori assegnati alla funzione con un nome e tipo: Name : Type |
genere | Restituisce il tipo di funzione |
Digita argomento | Digitare il parametro utilizzato nella programmazione generica (non necessariamente il tipo restituito) |
ArgName | Nome del valore assegnato alla funzione |
ArgType | Specifier di tipo per ArgName |
ArgNames | Elenco di ArgName separato da virgole |
Funzioni che assumono altre funzioni
Come visto in "Funzioni Lambda", le funzioni possono assumere altre funzioni come parametro. Il "tipo di funzione" che devi dichiarare funzioni che assumono altre funzioni è il seguente:
# Takes no parameters and returns anything
() -> Any?
# Takes a string and an integer and returns ReturnType
(arg1: String, arg2: Int) -> ReturnType
Ad esempio, potresti usare il tipo più vago, () -> Any?
, per dichiarare una funzione che esegue due volte una funzione lambda:
fun twice(x: () -> Any?) {
x(); x();
}
fun main() {
twice {
println("Foo")
} # => Foo
# => Foo
}
Funzioni Lambda
Le funzioni Lambda sono funzioni anonime che vengono solitamente create durante una chiamata di funzione per fungere da parametro di funzione. Sono dichiarati dalle espressioni circostanti con {parentesi} - se sono necessari argomenti, questi vengono messi prima di una freccia ->
.
{ name: String ->
"Your name is $name" //This is returned
}
L'ultima istruzione all'interno di una funzione lambda è automaticamente il valore di ritorno.
I tipi sono opzionali, se metti il lambda su un posto dove il compilatore può inferire i tipi.
Argomenti multipli:
{ argumentOne:String, argumentTwo:String ->
"$argumentOne - $argumentTwo"
}
Se la funzione lambda necessita solo argomento, allora la lista argomento può essere omesso e il singolo argomento indicate con it
invece.
{ "Your name is $it" }
Se l'unico argomento di una funzione è una funzione lambda, le parentesi possono essere completamente omesse dalla chiamata di funzione.
# These are identical
listOf(1, 2, 3, 4).map { it + 2 }
listOf(1, 2, 3, 4).map({ it + 2 })
Riferimenti di funzione
Possiamo fare riferimento a una funzione senza effettivamente chiamarla anteponendo il nome della funzione a ::
. Questo può quindi essere passato a una funzione che accetta qualche altra funzione come parametro.
fun addTwo(x: Int) = x + 2
listOf(1, 2, 3, 4).map(::addTwo) # => [3, 4, 5, 6]
Le funzioni senza ricevitore saranno convertite in (ParamTypeA, ParamTypeB, ...) -> ReturnType
dove ParamTypeA
, ParamTypeB
... sono il tipo di parametri della funzione e `ReturnType1 è il tipo di valore restituito dalla funzione.
fun foo(p0: Foo0, p1: Foo1, p2: Foo2): Bar {
//...
}
println(::foo::class.java.genericInterfaces[0])
// kotlin.jvm.functions.Function3<Foo0, Foo1, Foo2, Bar>
// Human readable type: (Foo0, Foo1, Foo2) -> Bar
Le funzioni con un ricevitore (che si tratti di una funzione di estensione o di una funzione membro) hanno una sintassi diversa. Devi aggiungere il nome del tipo del ricevitore prima dei due punti:
class Foo
fun Foo.foo(p0: Foo0, p1: Foo1, p2: Foo2): Bar {
//...
}
val ref = Foo::foo
println(ref::class.java.genericInterfaces[0])
// kotlin.jvm.functions.Function4<Foo, Foo0, Foo1, Foo2, Bar>
// Human readable type: (Foo, Foo0, Foo1, Foo2) -> Bar
// takes 4 parameters, with receiver as first and actual parameters following, in their order
// this function can't be called like an extension function, though
val ref = Foo::foo
Foo().ref(Foo0(), Foo1(), Foo2()) // compile error
class Bar {
fun bar()
}
print(Bar::bar) // works on member functions, too.
Tuttavia, quando il ricevitore di una funzione è un oggetto, il ricevitore viene omesso dall'elenco dei parametri, poiché questi sono e sono solo un'istanza di tale tipo.
object Foo
fun Foo.foo(p0: Foo0, p1: Foo1, p2: Foo2): Bar {
//...
}
val ref = Foo::foo
println(ref::class.java.genericInterfaces[0])
// kotlin.jvm.functions.Function3<Foo0, Foo1, Foo2, Bar>
// Human readable type: (Foo0, Foo1, Foo2) -> Bar
// takes 3 parameters, receiver not needed
object Bar {
fun bar()
}
print(Bar::bar) // works on member functions, too.
Dal momento che kotlin 1.1, il riferimento alla funzione può anche essere limitato a una variabile, che viene quindi chiamata riferimento a una funzione limitata .
fun makeList(last: String?): List<String> {
val list = mutableListOf("a", "b", "c")
last?.let(list::add)
return list
}
Nota questo esempio è dato solo per mostrare come funziona la funzione di riferimento limitata. È una cattiva pratica in tutti gli altri sensi.
C'è un caso speciale, però. Una funzione di estensione dichiarata come membro non può essere referenziata.
class Foo
class Bar {
fun Foo.foo() {}
val ref = Foo::foo // compile error
}
Funzioni base
Le funzioni sono dichiarate usando la fun
parola chiave, seguita da un nome di funzione e da qualsiasi parametro. È anche possibile specificare il tipo di ritorno di una funzione, che per impostazione predefinita è Unit
. Il corpo della funzione è racchiuso tra parentesi graffe {}
. Se il tipo di ritorno è diverso Unit
, il corpo deve emettere una dichiarazione di ritorno per ogni ramo di chiusura all'interno del corpo.
fun sayMyName(name: String): String {
return "Your name is $name"
}
Una versione abbreviata dello stesso:
fun sayMyName(name: String): String = "Your name is $name"
E il tipo può essere omesso poiché può essere dedotto:
fun sayMyName(name: String) = "Your name is $name"
Funzioni di stenografia
Se una funzione contiene solo un'espressione, possiamo omettere le parentesi graffe e usare invece un uguaglianza, come un'assegnazione di variabile. Il risultato dell'espressione viene restituito automaticamente.
fun sayMyName(name: String): String = "Your name is $name"
Funzioni in linea
Le funzioni possono essere dichiarate in linea usando il prefisso inline
e, in questo caso, si comportano come i macro in C, invece di essere chiamate, vengono sostituite dal codice del corpo della funzione in fase di compilazione. Ciò può portare a benefici prestazionali in alcune circostanze, principalmente laddove i lambda sono utilizzati come parametri di funzione.
inline fun sayMyName(name: String) = "Your name is $name"
Una differenza rispetto alle macro C è che le funzioni inline non possono accedere all'ambito da cui vengono chiamate:
inline fun sayMyName() = "Your name is $name"
fun main() {
val name = "Foo"
sayMyName() # => Unresolved reference: name
}
Funzioni dell'operatore
Kotlin ci consente di fornire implementazioni per un insieme predefinito di operatori con una rappresentazione simbolica fissa (come +
o *
) e una precedenza fissa. Per implementare un operatore, forniamo una funzione membro o una funzione di estensione con un nome fisso, per il tipo corrispondente. Funzioni che gli operatori di overload devono essere contrassegnati con il modificatore operator
:
data class IntListWrapper (val wrapped: List<Int>) {
operator fun get(position: Int): Int = wrapped[position]
}
val a = IntListWrapper(listOf(1, 2, 3))
a[1] // == 2
Altre funzioni dell'operatore possono essere trovate qui