智能播放和内部比较当“是”后的表情类型检查

根据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)不能将ab成它们的实际类型? 还是我错过了什么?

更新

即使ab的类型更改为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表达的问题。 你应该责怪类型系统。

abIntDouble实例,所以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 

但是, IntDouble同时是NumberComparable子类,而Kotlin不知道是否需要NumberComparable ,所以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 (而不是IntDoubleString )!

 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?! } 

是的,的确, aNumber一个实例。 但是请不要提及, < ,或者, compareTo 没有Number声明。 它在IntDouble :)。

编辑2

你说:

使用泛型力量ab是相同的类型。

所以试试这个:

 fun <A : Comparable<B>, B : Any> maxOf(a: A, b: B): Any = if (a < b) b else a 

你说:

如果ab的类型是Any则显式强制转换不是解决方案

  • 解决方案零:创建operator fun Any.compareTo
  • 解决方法一:放弃铸造。