智能播放和内部比较当“是”后的表情类型检查
根据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 = …): 在 kotlin.text中定义的 Int
这是因为smart-cast在评估表达式后(a is Int || a is Double) && (b is Int || b is Double)
不能将a
和b
成它们的实际类型? 还是我错过了什么?
更新
即使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 }
为什么会发生?
这不是什么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) aa() // 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
这就是为什么“错误”出现。
如何解决这个问题?
使用你的原始代码,或使用明确的演员(我知道它很烂,但这是一个不可避免的问题)。
我已经想出了一个美丽的解决方案! 看它:
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
:)。
编辑2
你说:
使用泛型力量
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
- 解决方法一:放弃铸造。