2017-03-12 1 views
5

ist hier ein minimales Beispiel, das das Problem veranschaulicht:Wie rufe ich Erweiterungsmethoden von außerhalb der Klasse auf, in der sie definiert sind?

abstract class Base { 
    abstract fun String.extension(x: Char) 
} 

class Derived : Base() { 
    override fun String.extension(x: Char) { 
     // Calling lots of methods on String, hence extension method 
     println("${first()} $length ${last()} ${firstOrNull { it == x }} ...") 
    } 
} 

die Erweiterungsmethode von Java Aufruf ist trivial:

Base o = new Derived(); 
o.extension("hello world", 'l'); 

Aber ich kann nicht herausfinden, wie es in der reinen Kotlin zu tun. Weder String noch Base scheint dieMethode zu haben.

Antwort

8

Erstens ist zu beachten, dass eine Erweiterungsfunktion als Mitglied definiert zwei Empfänger benötigt, einer eine Instanz des einschließenden Klasse (Dispatch Empfänger, gewöhnlich this der umschließenden Klasse) und die andere ist die Instanz der Typ, den die Funktion erweitert (Erweiterungsempfänger). Dies ist dokumentiert here.

Um also eine solche Funktion von außerhalb der Klasse aufzurufen, müssen Sie zwei Empfänger bereitstellen. Kotlin doesn't have any syntax zu tun, dass explizit wie (x, "abc").stringExtension(), aber Sie können den Versand Empfänger implizit liefern unter Verwendung eines extension lambda:

class C(val name: String) { 
    fun String.extended() = this + " extended by " + name 
} 

fun main(args: Array<String>) { 
    val c = C("c") 
    with(c) { println("abc".extended()) } 
} 

(runnable demo of this code)

Im with(...) { ... } Block wird c die implizite Empfänger, so dass Sie auf Verwenden Sie es als Versandempfänger in C Mitgliedererweiterungen. Dies würde mit einer anderen Funktion arbeiten, die Funktionstypen mit Empfängern verwendet: apply, run, use usw.

In Ihrem Fall wäre es with(o) { "hello world".extension('l') }

Wie @KirillRakhman erwähnte, eine Verlängerung Empfänger einer Erweiterungsfunktion für C sein auch implizit als Dispatch-Empfänger können für die Erweiterungen innerhalb C definiert verwendet:

fun C.someExtension() = "something".extended() 
+0

Sie können hinzufügen, dass Erweiterung _functions_ auch funktioniert. –

+0

@KirillRakhman, habe das nicht verstanden, könnten Sie bitte erklären? – hotkey

+1

Was ich meinte ist, dass nicht nur die Erweiterung _lambdas_, sondern auch extension_functions_ verwendet werden kann, um den impliziten Empfänger bereitzustellen. Beispiel: 'fun cinScope() =" ".extended()' –

0

Ihre Erweiterungsfunktion ist nur innerhalb der Base/Derived-Klasse definiert. Siehe Declaring Extensions as Members.

abstract class Base { 
    abstract fun String.extension(x: Char) 
} 

class Derived : Base() { 
    override fun String.extension(x: Char) { 
     // Calling lots of methods on String, hence extension method 
     println("${first()} $length ${last()} ${firstOrNull { it == x }} ...") 
    } 

    fun callExtension(c: Char) { 
     "hello".extension(c) 
    } 
} 

fun main(args: Array<String>) { 
    val base = Derived() 
    base.callExtension('h') 
} 
+1

Es gibt tatsächlich eine Möglichkeit, eine * public * -Elementerweiterung von außerhalb der Klasse aufzurufen: eine implizite Empfängerinstanz dieser Klasse zu verwenden. – hotkey

0

Um eine Erweiterung Methode außerhalb der Klasse décalé es verwenden, sollten Sie NICHT es innerhalb einer Klasse implementieren, und Sie sollten wie folgt tun:

package com.sample.test 

import java.io.File 

fun File.folderLength() : Long { 
    return 0L 
} 

So in Ihrer Klasse, die diese Methode aufrufen:

package com.sample.util 

import com.sample.test.* 
import java.io.File 

class foo{ 
    fun getFolderSize(url: String) : Long{ 
     var file = new File("...") 
     var length = file.folderLength() 
     return length 
    } 
} 

Hoffnung dies sollte Ihnen helfen.

Verwandte Themen