2017-07-12 49 views
5

Podczas wywoływania kodu Java z Kotlin, istnieje SAM conversion tak, że kod Java tak:Korzystanie funkcjonalne interfejsy z typów funkcji w Kotlin

adapter.setOnClickListener(new OnClickListener() { 
    @Override 
    public void onClick(View view, int position) { 
     // Do stuff here 
    } 
}); 

może wyglądać następująco:

adapter.setOnClickListener { view, position -> 
    // Do stuff 
} 

Teraz pracuję nad projektem Kotlin i chcę zdefiniować interfejs funkcjonalny jako odbiornik zdarzeń:

interface OnSomeActionListener { 

    fun onSomeAction(parameter1: Int, parameter2: String) 

} 

W SomeClass Mam funkcji, aby ustawić słuchacza:

... 

    private var onSomeActionListener: OnSomeActionListener? = null 

    fun setOnSomeActionListener(listener: OnSomeActionListener) { 
     onSomeActionListener = listener 
    } 

    ... 

I kiedy utworzyć wystąpienie tej klasy i spróbuj wywołać funkcję seter, robię to tak:

val thing = SomeClass() 

thing.setOnSomeActionListener(object : OnSomeActionListener { 
    override fun onSomeAction(parameter1: Int, parameter2: String) { 
     // Do stuff here 
    } 
}) 

I "Jestem świadomy, że Kotlin ma typy funkcji, dlatego nie obsługuje konwersji SAM z różnych stron, takich jak this one.

Przeczytałem trochę o typach funkcji, ale nie korzystałem z nich wcześniej.

W jaki sposób powinienem przepisać mój kod, aby móc wywołać funkcję ustawiającą w ten sposób?

val thing = SomeClass() 

thing.setOnSomeActionListener { parameter1, parameter2 -> 
    // Do stuff here 
} 

.

Odpowiedz

8

typ funkcji wygląda następująco:

(Parameters) -> ReturnType 

W twoim przypadku, zamiast za pomocą typ interfejsu, można użyć (View, Int) -> Unit. Byłoby to wyglądać mniej więcej tak:

private var onSomeActionListener: ((View, Int) -> Unit)? = null 

fun setOnSomeActionListener(listener: (View, Int) -> Unit) { 
    onSomeActionListener = listener 
} 

private fun callSomeActionListener(view: View, position: Int) { 
    onSomeActionListener?.invoke(view, position) 
} 

Dodaj nazwy

W typów funkcjonalnych można również określić nazwy parametrów. Nie zmienia to wiele pod maską, ale można dodać tu nieco klarowności i kod wywołujący, co jest miłe.

(view: View, position: Int) -> Unit 

Korzystanie typu alias

Aby uniknąć konieczności wpisywania (View, Int) -> Unit za każdym razem, można zdefiniować typealias:

typealias OnSomeActionListener = (view: View, position: Int) -> Unit 

więc, że Twój kod teraz wygląda tak ponownie:

private var onSomeActionListener: OnSomeActionListener? = null 

fun setOnSomeActionListener(listener: OnSomeActionListener?) { 
    onSomeActionListener = listener 
} 

I to nazwać:

val thing = SomeClass() 

thing.setOnSomeActionListener { view, position -> 
    // Do stuff here 
} 
+0

Dzięki za odpowiedź. Pomyślałem, że treść podzielona na jasne części i napisana jak przewodnik krok po kroku była bardzo pomocna. –

0

No, coś takiego:

// declare a variable of nullable function type: 
var onSomeActionListener: ((Int, String) -> Unit)? = null 

// declare higher-order function: 
fun setOnSomeActionListener(listener: (Int, String) -> Unit) { 
    onSomeActionListener = listener 
} 

// set listener: 
val listener: (Int, String) -> Unit = { p1, p2 -> { /* some stuff */ } } 
setOnSomeActionListener(listener) 

// or in one line: 
setOnSomeActionListener { p1, p2 -> { /* some stuff */ } } 

Aby uzyskać więcej informacji: Higher-Order Functions and Lambdas

0

Jak o definiowaniu funkcji, która akceptuje i zwraca funkcję interfejsu?

fun makeOnSomeActionListener(f: (Int,String) -> Unit) = object : OnSomeActionListener { 
    override fun onSomeAction(parameter1: Int, parameter2: String) = f(parameter1, parameter2) 
} 

Interfejs przekazuje pracę do f.

Następnie można napisać

val thing = SomeClass() 

thing.setOnSomeActionListener(makeOnSomeActionLisener { parameter1, parameter2 -> 
    // Do stuff here 
})