2016-06-22 21 views
2

Ich bin ein kotlin Neuling also vielleicht ist das trivial, aber ich habe keine relevante Hilfe bei Kotlinlang.org gefunden.Wie vermeide ich Objektausdrücke für Funktionen, die eine SAM-Schnittstelle zurückgeben

In einem Versuch, etwas über Kotlin zu lernen, ich mag PushStream Bibliothek zu implementieren.

Ich wollte die Grundtypen, so etwas definieren:

Typ-Aliase ist
typealias Receiver<T> = (T) -> bool 
typealias PushStream<T> = (Receiver<T>) -> Unit 

AFAIK nur Pseudo-Code so oben wird noch nicht unterstützt.

So war mein erster Versuch dies:

interface Receiver<T> : (T) -> Boolean { 
} 

interface PushStream<T> : (Receiver<T>) -> Unit { 
} 

fun <T> singleton (v : T) : PushStream<T> { 
    return { r : Receiver<T> -> r (v) } 
} 

Kotlin sagt dann:

Error:(10, 12) Kotlin: Type mismatch: inferred type is (Receiver<T>) -> Boolean but PushStream<T> was expected 

Ich scheine mit um es bekommen zu können:

fun <T> singleton (v : T) : (Receiver<T>) -> Unit { 
    return { r : Receiver<T> -> r (v) } 
} 

Aber das ist nicht die Signatur, die ich speziell für die fortgeschritteneren Operatoren benötige, die ich möglicherweise benötigen, um den vollen Funktionstyp anzugeben:

fun <T> singleton (v : T) : ((T) -> Boolean) -> Unit { 
    return { r : Receiver<T> -> r (v) } 
} 

Dies ist, glaube ich, macht die API schwerer zu lesen.

Was ich tun könnte, um ein Objekt unter Verwendung des Ausdrucks:

fun <T> singleton (v : T) : PushStream<T> { 
    return object : PushStream<T> { 
     operator override fun invoke (r : Receiver<T>) : Unit { 
      r (v) 
     } 
    } 
} 

Dies funktioniert, aber ich mag Lambda-Ausdrücke verwenden Sie den Code eines prägnanten zu halten.

Alle Tipps willkommen. Auch wenn Sie wissen, dass es interessante Blogs/Präsentationen zur Programmierung mit Funktionen höherer Ordnung in Kotlin gibt, die ebenfalls sehr geschätzt werden.

+2

Kotlin die Wahl implizite SAM-Schnittstelle Umwandlung zu unterstützen funktioniert nur für Java-Schnittstellen. Nicht für Kotlin-Schnittstellen. Ich stimme zu, dass dies in einigen Fällen die Lesbarkeit beeinträchtigt. Type-Aliase werden in der nächsten Version (AFAIR) kommen. JetBrains wird dann sehen, ob das das Problem behebt, ob die Konvertierung von Kotlin-Schnittstellen erlaubt sein sollte. Hierfür gibt es eine Funktion: https://youtrack.jetbrains.com/issue/KT-7770. In der Zwischenzeit würde ich einfach "(T) -> Boolean" in den Signaturen verwenden. Hoffentlich ist es nicht zu schwer, den Code mit Typ-Aliasen zu überarbeiten. –

Antwort

2

Da es (noch) keine Typen-Aliase gibt, können sich Typ-Signaturen nicht gegenseitig ersetzen. In Ihrem Fall müssen Sie Komposition statt Vererbung verwenden, um eine Abstraktionsebene zu erstellen:

open class Receiver<T>(val op: (T) -> Boolean) 

open class PushStream<T>(val op: (Receiver<T>) -> Unit) 

fun <T> singleton (v: T): PushStream<T> { 
    return PushStream<T> { r -> r.op(v) } 
} 

I ersetzt Schnittstellen mit Klassen, weil ich den Rest des Codes nicht sehen. Wenn Sie Schnittstellen benötigen, dann Fabrik Funktionen nutzen:

interface Receiver<T> { 
    val op: (T) -> Boolean 
} 

fun <T> receiver(op: (T) -> Boolean) = object : Receiver<T> { 
    override val op = op 
} 
+1

Danke für die Idee. – FuleSnabel

1

Wenn Sie die PushStream-Interface in Java definieren, können Sie es so verwenden:

fun <T> singleton (v : T) : PushStream<T> { 
    return PushStream { r : Receiver<T> -> r (v) } 
}