Metodi di estensione statica a Kotlin


142

Come si definisce un metodo di estensione statica in Kotlin? È possibile? Al momento ho un metodo di estensione come mostrato di seguito.

public fun Uber.doMagic(context: Context) {
    // ...
}

L'estensione sopra può essere invocata su un'istanza.

uberInstance.doMagic(context) // Instance method

ma come posso renderlo un metodo statico come mostrato di seguito.

Uber.doMagic(context)         // Static or class method

1
Cosa intendi con "metodo di estensione statica"?
Andrey Breslav,

3
Un metodo che posso chiamare senza un'istanza, ma è ancora un'estensione della classe. (Metodi statici Java regolari)
Ragunath Jawahar,

Penso che potrebbe non essere l'uso previsto delle estensioni di Kotlin , ho pensato alla stessa cosa mentre cercavo di estrapolare il concetto di C #. Ma mentre in pratica l'utilizzo è abbastanza simile. Le estensioni di Kotlin, mentre affermano di essere spedite staticamente, si sentono dinamicamente "attaccate", se esiste una cosa del genere, o in ritardo nell'istanza. Se non sbaglio ... o forse ho sbagliato completamente :)
Dan

7
Attualmente non è possibile scrivere un metodo di estensione che verrebbe chiamato su un nome di classe anziché sull'istanza di classe. In effetti, la funzione di estensione accetta un parametro del ricevitore che è un'istanza, quindi non c'è modo di saltare questa parte. D'altra parte, stiamo lavorando a un modo di scrivere estensioni per gli oggetti di classe, in modo da poterlo chiamare con un nome di classe, ma il destinatario ha il tipo di oggetto di classe
Andrey Breslav,

@AndreyBreslav Puoi aggiornarci se sono consentite le funzioni di estensione statica? Anche a me manca.
Lars Blumberg,

Risposte:


143

Per raggiungere questo obiettivo Uber.doMagic(context), è possibile scrivere un'estensione sull'oggetto associato di Uber(è richiesta la dichiarazione dell'oggetto associato):

class Uber {
    companion object {}
}

fun Uber.Companion.doMagic(context: Context) { }

79
Questo è carino ma cosa succede se si tratta di una classe Java o di una classe senza un compagno?
Jire,

31
@Jire per questi casi, non c'è supporto in Kotlin 1.0
Andrey Breslav,

2
Ho potuto vedere un caso d'uso nell'estensione delle classi del framework JVM con valori predefiniti, ad esempio String.DEFAULT o Int.DEFAULT, nel caso in cui la logica del dominio lo richieda (la mia attualmente lo fa, insieme a classi di dati vuote).
Steffen Funke,

36
Funziona solo finché Uber è una classe di Kotlin . Sarebbe bello avere la possibilità di estendere staticamente anche le classi Java
kosiara - Bartosz Kosarzycki

6
Questo non è ancora possibile, come si può vedere qui: youtrack.jetbrains.com/issue/KT-11968 C'è un relativo filo ecco: stackoverflow.com/questions/33911457/...
NARKO

12

Questo è ciò che dice la documentazione ufficiale:

Kotlin genera metodi statici per funzioni a livello di pacchetto. Kotlin può anche generare metodi statici per le funzioni definite in oggetti con nome o oggetti associati se si annotano tali funzioni come @JvmStatic. Per esempio:

Metodi statici di Kotlin

class C {
  companion object {
    @JvmStatic fun foo() {}
    fun bar() {}
  }
}

Ora, foo () è statico in Java, mentre bar () non è:

C.foo(); // works fine
C.bar(); // error: not a static method

8

In realtà ho avuto questa domanda esatta 30 minuti fa, quindi ho iniziato a scavare e non sono riuscito a trovare alcuna soluzione o soluzione alternativa, MA durante la ricerca ho trovato questa sezione sul sito Web di Kotlinglang che afferma che:

Si noti che le estensioni possono essere definite con un tipo di ricevitore nullable. Tali estensioni possono essere richiamate su una variabile oggetto anche se il suo valore è nullo.

Quindi ho avuto l'idea più folle di sempre, perché non definire una funzione di estensione con un ricevitore nullable (senza effettivamente utilizzare quel ricevitore) e quindi chiamarla su un oggetto null! Quindi l'ho provato, e ha funzionato abbastanza bene, ma sembrava così brutto. Era così:

(null as Type?).staticFunction(param1, param2)

Quindi ho aggirato il problema creando un valore nel mio file delle estensioni del tipo destinatario che aveva un valore null e quindi lo usavo nell'altra mia classe. Quindi, ad esempio, ecco come ho implementato una funzione di estensione "statica" per la Navigationclasse in Android: Nel mio file NavigationExtensions.kt:

val SNavigation: Navigation? = null
fun Navigation?.createNavigateOnClickListener(@IdRes resId: Int, args: Bundle? = null, navOptions: NavOptions? = null,
                                                navigationExtras: Navigator.Extras? = null) : (View) -> Unit {
    //This is just implementation details, don't worry too much about them, just focus on the Navigation? part in the method declaration
    return { view: View -> view.navigate(resId, args, navOptions, navigationExtras) }
}

Nel codice che lo utilizza:

SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)

Ovviamente, questo non è un nome di classe, è solo una variabile del tipo di classe che ha un valore nullo. Questo è ovviamente brutto dal lato del produttore dell'estensione (perché devono creare la variabile) e dal lato dello sviluppatore (perché devono usare il STypeformato anziché il nome della classe effettiva), ma è il più vicino che può essere raggiunto in questo momento rispetto alle effettive funzioni statiche. Si spera che i produttori di lingue Kotlin risponderanno al problema creato e aggiungano tale funzionalità nella lingua.


2
Hacky questo potrebbe essere. Ma anche intelligente. Questa è la risposta più perspicace alla domanda. Kotlin sta facendo del suo meglio per falsificare fornendo estensioni di prima classe, quindi IMO, usi le soluzioni migliori che puoi per gestire le sue inanità. Bello.
Travis Griggs,

5

Puoi creare un metodo statico usando l'oggetto Companion come:

class Foo {
    // ...
    companion object {
        public fun bar() {
            // do anything
        }
    }
}

e quindi puoi chiamarlo come:

class Baz {
    // ...
    private fun callBar() {
        Foo.bar()
    }
}

Credo che in realtà non sia statico. Gli oggetti companion consentono di chiamare utilizzando il nome della classe, ma utilizza comunque un'istanza della classe. Inoltre, la domanda riguardava le funzioni di estensione statica, non solo le funzioni statiche. Tuttavia per avere funzioni statiche è possibile utilizzare l' platformStaticannotazione.
Ragunath Jawahar,

1
platformStaticfu ribattezzato JvmStaticnell'attuale Kotlin.
Jayson Minard,

0

Ti consiglio di guardare questo link. Come puoi vedere lì, dovresti semplicemente dichiarare il metodo al livello più alto del pacchetto (file):

package strings
public fun joinToString(...): String { ... }

Questo è uguale a

package strings;

public class JoinKt {
    public static String joinToString(...) { ... }
}

Con constan tutto è uguale. Questa dichiarazione

val UNIX_LINE_SEPARATOR = "\n"

è uguale a

public static final String UNIX_LINE_SEPARATOR = "\n";

-3

Mi piace anche avere la possibilità di aggiungere metodi di estensione statica in Kotlin. Come soluzione alternativa per ora sto aggiungendo il metodo exntension a più classi invece di utilizzare un metodo di estensione statica in tutte.

class Util    

fun Util.isDeviceOnline(context: Context): Boolean {
    val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = connMgr.activeNetworkInfo
    return networkInfo != null && networkInfo.isConnected
}

fun Activity.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }
fun OkHttpClient.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }

2
La domanda originale era su come estendere un javaclass con un metodo statico . Nel tuo caso, ciò significa essere in grado di chiamare letteralmente Activity.isDeviceOnline(...)senza avere un'istanza di Activity.
Fabian Zeindl,

-4

Per creare un metodo di estensione in kotlin devi creare un file kotlin (non una classe) quindi dichiarare il tuo metodo nel file Ad esempio:

public fun String.toLowercase(){
    // **this** is the string object
}

Importa la funzione nella classe o nel file su cui stai lavorando e usala.


Il titolo non è nemmeno una domanda
daniel.jbatiz il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.