2016-12-17 31 views
10

Chcę skorzystać z kotlin, gdy wyrażenia i ogólne metody upraszczają wspólne preferencje API Androida.Kotlin - kiedy wyrażenie z funkcją zwrotu funkcji

Zamiast wywoływać getString() & getInt() itd. Przez cały czas, chcę utworzyć funkcję rozszerzenia, która będzie przełączać się w zależności od typu funkcji zwracanej i wywoływać odpowiednią metodę. Coś jak poniżej:

fun <T> SharedPreferences.get(key: String): T? { 
     when (T) { //how do I switch on return type and call appropriate function? 
      is String -> getString(key, null) 
      is Int -> getInt(key, -1) 
      is Boolean -> getBoolean(key, false) 
      is Float -> getFloat(key, -1f) 
      is Long -> getLong(key, -1) 
     } 
     return null 
    } 

Oczywiście, nie zadziała. Ale czy istnieje jakieś rozwiązanie do użycia, gdy wyrażenie dla typu zwrotu funkcji? Wszystkie sugestie są mile widziane.

Odpowiedz

9

Aby osiągnąć dokładnie to, co chcesz, możesz użyć reified type parameters. Spowoduje to, że kompilator wstawi swoją funkcję w swoich witrynach wywoływania, zastępując numer T typem używanym w witrynie połączenia.

Funkcja wyglądałby następująco:

@Suppress("IMPLICIT_CAST_TO_ANY") 
inline operator fun <reified T> SharedPreferences.get(key: String): T? = 
    when (T::class) { 
     String::class -> getString(key, null) 
     Int::class -> getInt(key, -1) 
     Boolean::class -> getBoolean(key, false) 
     Float::class -> getFloat(key, -1f) 
     Long::class -> getLong(key, -1) 
     else -> null 
    } as T? 

Jeśli się getoperator function, można również nazwać używając składni operatora: prefs[name].

Połączenia powinny, oczywiście, zapewnić wystarczająco dużo informacji o typie dla kompilator wywnioskować T:

val i: Int? = prefs["i"] // OK, the type information is taken from the declaration 
val j: Int = prefs["i"]!! // OK 

val x = prefs["x"] // Error, not enough type information 
val y = prefs.get<String>("y") // OK, the type will be `String?` 

fun f(z: Int) = z 
f(prefs["z"]!!) // OK, the type information is taken from the parameter type 
+0

interesujący ... dzięki. Ale "To sprawi, że kompilator wbuduje twoją funkcję". Czy możesz mi wyjaśnić, co robi faktoring? Czytam dokumenty, ale pokazuje, że wstawianie jest związane z czymś innym, niż [wydajność] (http://stackoverflow.com/a/145841/3830694). Nie jestem ekspertem. Czy możesz wyjaśnić w prosty sposób, co właściwie robi inline? –

+1

@KrupalShah, w Kotlin, [funkcje "wbudowane"] (https://kotlinlang.org/docs/reference/inline-functions.html) rzeczywiście nie mają być narzędziem wydajności, ponieważ sama JVM zarządza funkcjami inline w czasie wykonywania dość. Zamiast tego funkcje "inline" są używane dla elastyczności. Dwa główne przypadki użycia to [zmienione parametry typu] (https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters) i [nielokalny przepływ kontrolny] (https: // kotlinlang .org/docs/reference/inline-functions.html # non-local-zwraca) ('break' i' continue' mogą zostać dodane do 'return' w przyszłości). – hotkey

+1

@KrupalShah, należy zauważyć, że oba przypadki użycia wymagają transformacji treści funkcji (w przypadku reifikowanych generycznych parametr typu jest zastępowany typem obecnym w witrynie wywołania, ponieważ w przeciwnym razie parametr type zostanie [usunięty] (https: // docs .oracle.com/javase/tutorial/java/generics/erasure.html), a kod nie mógł go użyć, w przypadku przepływu kontrolnego argument funkcyjny jest wstawiany, więc 'return' w nim będzie działał z funkcją zewnętrzną) . Te transformacje są wykonywane dla każdego z wywołań funkcji, a transformowany kod jest następnie zaznaczany na stronach wywołań. – hotkey