这样的东西只能用平等判断when
.不清楚你想在这样的情况下发生什么:
when (foo) {
is Int -> { ... }
is String -> { ... }
in someList -> { ... }
else -> // what values would "the options known by a 'when'" be?
}
要对when
进行实际操作,您需要某种批注处理来查看when
表达式,并生成绑定值的列表.没有语言功能可以做到这一点.
我建议你只写你自己的when
种.一个简单的实施是:
fun <T, R> `when`(target: T, vararg clauses: Pair<T, () -> R>, `else`: (Set<T>) -> R) {
(clauses.firstOrNull { it == target }?.second?.invoke()) ?:
`else`(clauses.map { it.first }.toSet())
}
`when` (cat,
Fat to {},
Greedy to {},
`else` = { boundValues ->
throw RuntimeException("You have a $cat cat - I only know about ${ boundValues.joinToString { it.toString() } }.")
}
)
当然,您可以通过使用DSL builder模式使其看起来更类似于实际的when
.例如,这里我实现了一个支持在一个子句中放置多个值的子句.
data class WhenClause<T, R>(val matchedValues: List<T>, val action: () -> R) {
fun evaluate(value: T): R? =
action.takeIf { value in matchedValues }?.invoke()
}
class WhenContext<T, R> {
private val clauses = mutableListOf<WhenClause<T, R>>()
private var `else`: ((Set<T>) -> R)? = null
fun evaluate(value: T) =
clauses.firstNotNullOfOrNull { it.evaluate(value) } ?:
`else`?.invoke(clauses.flatMap { it.matchedValues }.toSet()) ?:
error("Not exhaustive")
infix fun T.then(block: () -> R) {
clauses.add(WhenClause(listOf(this), block))
}
infix fun T.or(other: T) = listOf(this, other)
infix fun List<T>.or(other: T) = plusElement(other)
infix fun List<T>.then(block: () -> R) {
clauses.add(WhenClause(this, block))
}
fun `else`(block: (Set<T>) -> R) {
this.`else` = block
}
}
inline fun <T, R> `when`(value: T, block: WhenContext<T, R>.() -> R): R {
val context = WhenContext<T, R>()
context.block()
return context.evaluate(value)
}
用法示例:
`when` (cat) {
(Fat or Greedy) then { }
`else` { boundValues ->
throw RuntimeException("You have a $cat cat - I only know about ${ boundValues.joinToString { it.toString() } }.")
}
}