我正在研究像这样的扩展方法:
infix fun <T> T.isNullOr(other: T): Boolean {
if (this == null) return true
return this == other
}
并且我正在尝试使用这种方法。
val thisShouldWork = true isNullOr true // this is true
val thisShouldNotWork = true isNullOr 0 // No compilation errors?
我期望编译错误,因为Boolean
的type参数自动设置为isNullOr
,但不是。发生什么事了?
我误会吗?
在C#中,相同的代码可以正常工作。
static bool IsNullOr<T>(this T t, T other) {
if (t == null) return true;
return Equals(t, other);
}
bool howAboutThis = 0.IsNullOr(0);
bool andThis = 0.IsNullOr(false); // error - cannot detect type parameter for this
答案 0 :(得分:3)
在这里,val thisShouldNotWork = true isNullOr 0
等于val thisShouldNotWork: Boolean = true.isNullOr<Any>(0)
。类型参数推断为最接近的父级。
函数的返回类型基于逻辑表达式求值:this == other
。让我们看一下==
函数声明:public open operator fun equals(other: Any?): Boolean
。它收到Any?
。
此函数中的Type参数与Boolean
无关。
答案 1 :(得分:1)
我认为在这种情况下,泛型并不重要。您只需在方法中调用equals
,即可对任何类型进行调用。它基本上与:
infix fun Any.isNullOr(other: Any): Boolean {
return this == other
}
它可以毫无问题地进行编译,因为您可以随时调用equals
答案 2 :(得分:1)
请记住,泛型类型信息会在运行时删除,并且每当您尝试将某种东西放入接受泛型的方法中时,都将使用公共分母,例如:
listOf("one", 123) // -> assumes T:Any and therefore gives List<Any>
在您的示例中,这意味着"one".isNullOr(123)
都变成Any
。
不过,作为旁注,如果您声明一个特定类型(例如List<String>
),如下所示,则不能为它分配其他类型:
val test : List<String> = listOf(123) // this will not work
在编译时已经知道给定的int不能成为字符串。但是,此示例对您没有帮助,因为您没有返回该泛型类型。如果您的方法看起来有些不同,例如将具有通用类型作为返回值,它可能很容易像以前的List
-sample一样得出结果。
因此,要修复示例,您需要指定基本上会使infix
过时的类型,例如以下将按您期望的那样工作:
val someString : String? = TODO()
val works = someString.isNullOr<String?>("other")
val doesntWork = someString.isNullOr<Int?>(123) // does not nor does:
val doesntWorkToo = someString.isNullOr<String?>(123)
请注意,对于您所展示的内容,某些标准功能可能会有所帮助(但不能消除该特定问题),即,将?:
(elvis operator)与?.let
一起使用:
val someVal : String? = "someString given from somewhere"
val thisWorks = someVal?.let {
it == "some other string to compare"
} ?: true /* which basically means it was null */
val thisWillNot = someVal?.let {
it == 123 // compile error (funny enough: it.equals(123) would work ;-)
} ?: true /* it is null */
答案 3 :(得分:0)
感谢答案。我认为没有办法在编译级别阻止这种情况,因此我决定检查other
的类型。
inline infix fun <reified T> T.isNullOr(other: T): Boolean {
if (this == null) return true
if (other !is T) return false
return this == other
}
答案 4 :(得分:0)
如果您真的想阻止它,可以:
class IsNullOr<T>(val x: T) {
operator fun invoke(other: T): Boolean {
if (x == null) return true
return x == other
}
}
fun <T> T.isNullOr() = IsNullOr(this)
fun main(args: Array<String>) {
val thisShouldWork = true.isNullOr()(true) // compiles
val thisShouldNotWork = true.isNullOr()(0) // doesn't compile
}
这使得类型推断仅取决于isNullOr
的接收者。如果val
是通用的,您甚至可以保留原始语法(但不能保留)。