根据When Expression的文档,它可以替换“if-else if”,所以我尝试实现一个函数来返回Any
类型的两个变量的最大值:
fun maxOf(a: Any, b: Any) = when {
a is Int && b is Int -> if (a < b) b else a
a is Double && b is Double -> if (a < b) b else a
a is Int && b is Double -> if (a < b) b else a
a is Double && b is Int -> if (a < b) b else a
a is String && b is String -> if (a < b) b else a
else -> null
}
上述实现有效,但我认为它可以更简洁:
fun maxOf(a: Any, b: Any) = when {
(a is Int || a is Double) && (b is Int || b is Double) -> if (a < b) b else a
a is String && b is String -> if (a < b) b else a
else -> null
}
但我失败了,因为第二次实施不起作用;错误发生在第一次出现if (a < b)
:
未解决的参考资料。
由于接收器类型不匹配,以下候选者均不适用
• public fun String.compareTo(other:String,ignoreCase:Boolean = ...):Int 在 kotlin.text中定义
这是因为智能广播在评估表达式a
后无法将b
和(a is Int || a is Double) && (b is Int || b is Double)
投射到实际类型吗?或者我错过了什么?
即使a
和b
的类型更改为Number
,也会发生同样的错误:
fun maxOf(a: Number, b: Number) = when {
(a is Int || a is Double) && (b is Int || b is Double) -> if (a < b) b else a
else -> null
}
答案 0 :(得分:3)
这不是when
表达的问题。你应该责怪类型系统。
a
和b
是Int
和Double
的实例,因此Kotlin会将其推断为他们的LCA。例如:
open class A { fun a() = println("meow meow meow") }
class B : A()
class C : A()
if (a is B || a is C) a.a() // smart cast works
但是,Int
和Double
同时是Number
和Comparable
的子类,Kotlin不知道您是否需要Number
或Comparable
,因此Kotlin将其视为Any
的实例。
if (a is Int || a is Double)
if (a > 1) print("meow meow") // smart cast doesn't work
这就是出现“bug”的原因。
使用原始代码,或使用显式强制转换(我知道它很糟糕,但 确实是一个不可避免的问题)。 德尔>
我想出了一个漂亮的解决方案!看看它:
fun <T : Comparable<T>> maxOf(a: T, b: T): T? = when {
(a is Int || a is Double) && (b is Int || b is Double) -> if (a < b) b else a
a is String && b is String -> if (a < b) b else a
else -> null
}
通过这种方式,您可以对其应用Comparable
(而不仅仅是Int
,Double
和String
)!
fun <T : Comparable<T>> maxOf(a: T, b: T): T = if (a < b) b else a
如果输入无效,原始版本将返回null
,如果输入无效,此版本将引发编译错误,帮助您在编译时发现错误。
你评论过我并提出了进一步的问题。我想让我的回复更具可读性,所以我会把它添加到我的回答中。
fun someFunction(a: Number) {
if (a is Int || a is Double) println(a < 1) // still error! Why?!
}
是的,确实,a
是Number
的实例。
但请注意,<
或compareTo
,Number
中声明 。它位于Int
或Double
:)。
你说:
使用泛型强制
a
和b
属于同一类型。
所以试试这个:
fun <A : Comparable<B>, B : Any> maxOf(a: A, b: B): Any = if (a < b) b else a
你说:
如果a
和b
的类型为Any
,显式广告不是解决方案
operator fun Any.compareTo