简体   繁体   中英

Combining Function Type in Kotlin with 'or'

I'm pretty new to Kotlin and wondered if you can combine a list of function type into a single function.

I have an interface presents a filter, and some predefined filters:

interface Filter : (Int) -> Boolean {
    val a: Int
}

class FilterA(override val a: Int) : Filter {

    override fun invoke(numberToFilter: Int): Boolean {
        ....
    }
}

class FilterB(override val a: Int) : Filter {

    override fun invoke(numberToFilter: Int): Boolean {
        ....
    }
}

I'm now have a list of Filter object, which I want to combine using inclusive disjunction OR , so that I can passed that to a filter a list of Int. For example:

val combinedFilter = listOf(FilterA(a), FilterB(b)). { `do something here` }

val filteredInt = listToBeFiltered.filter { combinedFilter }

However, I'm somehow stuck in defining the do something here part. I believe you can use reduce method to do it, but it keeps telling me error somehow. Below is how I tried it

val combinedFilter = listOfFilters.reduce { filterA, filterB -> { filterA or filterB } }

infix fun <T> ((T) -> Boolean).or(that: (T) -> Boolean): (T) -> Boolean = { this(it) || that(it) }

But got

Type mismatch.
Required:
Filter
Found:
() → (Int) → Boolean

I believe I did something wrong with the syntax. Hope that you guys can help. Thanks.

That's because you wrapped the expression in an extra lambda, also the type of the accumulator in reduce wiil be Filter for your listOfFilters but or returns (T) -> Boolean . You can fix this by specifying the type of accumulator and getting rid of extra lambda:

val combinedFilter = listOfFilters.reduce<(Int) -> Boolean, Filter> { filterA, filterB -> filterA or filterB }

But there is a better way to do it without allocating a lot of lambdas:

val combinedFilter = { x: Int -> listOfFilters.any { filter -> filter(x) } }
val filteredInt = listToBeFiltered.filter(combinedFilter)

or

fun <T> List<(T) -> Boolean>.combineAny() = { x: T -> this.any { filter -> filter(x) } }
val combinedFilter = listOfFilters.combineAny()
val filteredInt = listToBeFiltered.filter(combinedFilter)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM