Méthodes d'extension statique dans Kotlin

142

Comment définir une méthode d'extension statique dans Kotlin? Est-ce seulement possible? J'ai actuellement une méthode d'extension comme indiqué ci-dessous.

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

L'extension ci-dessus peut être appelée sur une instance.

uberInstance.doMagic(context) // Instance method

mais comment puis-je en faire une méthode statique comme indiqué ci-dessous.

Uber.doMagic(context)         // Static or class method
Ragunath Jawahar
la source
1
Qu'entendez-vous par «méthode d'extension statique»?
Andrey Breslav
3
Une méthode que je peux appeler sans instance, mais qui est toujours une extension de la classe. (Méthodes statiques Java régulières)
Ragunath Jawahar
Je pense que ce n'est peut-être pas l'usage prévu de la bonne question des extensions Kotlin , j'ai pensé à la même chose en essayant d'extrapoler le concept C #. Mais alors que dans la pratique, l'utilisation est assez similaire. Les extensions Kotlin, bien qu'elles prétendent être distribuées statiquement, elles se sentent comme dynamiquement «attachées», s'il y a une telle chose, ou liées tardivement à l'instance. Si je ne me trompe pas ... ou peut-être que je me suis complètement trompé :)
Dan
7
Actuellement, vous ne pouvez pas écrire une méthode d'extension qui serait appelée sur un nom de classe par opposition à une instance de classe. En effet, la fonction d'extension prend un paramètre de récepteur qui est une instance, il n'y a donc aucun moyen de sauter cette partie. D'autre part, nous travaillons sur un moyen d'écrire des extensions aux objets de classe, de sorte que vous l'appeliez sur un nom de classe, mais le récepteur a le type de l'objet de classe
Andrey Breslav
@AndreyBreslav Pouvez-vous nous mettre à jour si les fonctions d'extension statiques seront autorisées? Ça me manque aussi.
Lars Blumberg

Réponses:

143

Pour ce faire Uber.doMagic(context), vous pouvez écrire une extension à l' objet compagnon de Uber(la déclaration d'objet compagnon est requise):

class Uber {
    companion object {}
}

fun Uber.Companion.doMagic(context: Context) { }
Andrey Breslav
la source
79
C'est bien mais que faire si c'est une classe Java ou une classe sans compagnon?
Jire
31
@Jire pour de tels cas, il n'y a pas de support dans Kotlin 1.0
Andrey Breslav
2
Je pourrais voir un cas d'utilisation dans l'extension des classes de cadre JVM avec des valeurs par défaut, par exemple String.DEFAULT ou Int.DEFAULT, au cas où votre logique de domaine l'exigerait (la mienne le fait actuellement, en conjonction avec des classes de données vides).
Steffen Funke
36
Cela ne fonctionne que tant qu'Uber est une classe Kotlin . Ce serait bien d'avoir la possibilité d'étendre statiquement les classes Java également
kosiara - Bartosz Kosarzycki
6
Ce n'est toujours pas possible comme vous pouvez le voir ici: youtrack.jetbrains.com/issue/KT-11968 Il y a un fil SO associé ici: stackoverflow.com/questions/33911457/…
narko
12

Voici ce que dit la documentation officielle:

Kotlin génère des méthodes statiques pour les fonctions au niveau du package. Kotlin peut également générer des méthodes statiques pour les fonctions définies dans des objets nommés ou des objets compagnons si vous annotez ces fonctions comme @JvmStatic. Par exemple:

Méthodes statiques Kotlin

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

Maintenant, foo () est statique en Java, alors que bar () ne l'est pas:

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

En fait, j'avais cette question exacte il y a 30 minutes, alors j'ai commencé à fouiller et je n'ai pas trouvé de solution ou de contournement pour cela, MAIS en cherchant, j'ai trouvé cette section sur le site Web de Kotlinglang qui indique que:

Notez que les extensions peuvent être définies avec un type de récepteur Nullable. De telles extensions peuvent être appelées sur une variable objet même si sa valeur est nulle.

Alors j'ai eu l'idée la plus folle de tous les temps, pourquoi ne pas définir une fonction d'extension avec un récepteur nullable (sans utiliser réellement ce récepteur) et l'appeler ensuite sur un objet nul! Alors j'ai essayé ça, et ça a plutôt bien marché, mais ça avait l'air si moche. C'était comme ça:

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

J'ai donc contourné cela en créant un val dans mon fichier d'extensions du type de récepteur qui avait une valeur de null, puis je l'ai utilisé dans mon autre classe. Donc, à titre d'exemple, voici comment j'ai implémenté une fonction d'extension "statique" pour la Navigationclasse sous Android: Dans mon fichier 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) }
}

Dans le code qui l'utilise:

SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)

Evidemment, ce n'est pas un nom de classe, c'est juste une variable du type de classe qui a une valeur nulle. C'est évidemment moche du côté des fabricants d'extensions (car ils doivent créer la variable) et du côté des développeurs (car ils doivent utiliser le STypeformat au lieu du nom de classe réel), mais c'est le plus proche qui peut être atteint maintenant par rapport aux fonctions statiques réelles. Espérons que les créateurs de langage Kotlin répondront au problème qui a été créé et ajouteront cette fonctionnalité dans la langue.

kyay
la source
2
Hacky c'est peut-être. Mais aussi cool intelligent. C'est la réponse la plus perspicace à la question. Kotlin fait de son mieux pour simuler la fourniture d'extensions de première classe, donc l'OMI, vous utilisez les meilleures solutions pour faire face à ses inanités. Agréable.
Travis Griggs
5

Vous pouvez créer une méthode statique en utilisant un objet Companion comme:

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

et ensuite vous pouvez l'appeler comme:

class Baz {
    // ...
    private fun callBar() {
        Foo.bar()
    }
}
bbarm
la source
Je pense que ce n'est pas vraiment statique. Les objets compagnons vous permettent d'appeler en utilisant le nom de la classe, mais utilisent toujours une instance de la classe. En outre, la question portait sur les fonctions d'extension statiques, pas seulement sur les fonctions statiques. Cependant, pour avoir des fonctions statiques, vous pouvez utiliser l' platformStaticannotation.
Ragunath Jawahar
1
platformStatica été renommé JvmStaticdans Kotlin actuel.
Jayson Minard
0

Je vous recommande de regarder ce lien. Comme vous pouvez le voir, vous devez simplement déclarer la méthode au niveau supérieur du package (fichier):

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

C'est égal à

package strings;

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

Avec constans, tout est pareil. Cette déclaration

val UNIX_LINE_SEPARATOR = "\n"

est égal à

public static final String UNIX_LINE_SEPARATOR = "\n";
Nisazh
la source
-3

J'aime aussi beaucoup avoir la possibilité d'ajouter des méthodes d'extension statiques dans Kotlin. Comme solution de contournement pour l'instant, j'ajoute la méthode d'extension à plusieurs classes au lieu d'utiliser une seule méthode d'extension statique dans chacune d'elles.

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) }
Kosiara - Bartosz Kosarzycki
la source
2
La question initiale était de savoir comment une javaclass peut être étendue avec une méthode statique . Dans votre cas, cela signifie être capable d'appeler littéralement Activity.isDeviceOnline(...)sans avoir d'instance de Activity.
Fabian Zeindl
-4

Pour créer une méthode d'extension dans kotlin, vous devez créer un fichier kotlin (pas une classe) puis déclarer votre méthode dans le fichier Ex:

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

Importez la fonction dans la classe ou le fichier sur lequel vous travaillez et utilisez-la.

daniel.jbatiz
la source
Le titre n'est même pas une question
daniel.jbatiz