Kotlin - 检查通用参数是否可选?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin - 检查通用参数是否可选?相关的知识,希望对你有一定的参考价值。
我正在编写这个通用方法来从firebase获取数据?在某些情况下,返回null是有效的,在其他情况下不是,是否可以检查通用参数是否可以为空?
前
reference.obsrveObject(User.class)
应该抛出null
reference.obsrveObject(User?.class)
应该使用null值调用onNext
fun DatabaseReference.observeSingleEvent(): Observable<DataSnapshot?> {
return Observable.create { subscriber ->
val valueEventListener = object: ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot?) {
subscriber.onNext(snapshot)
subscriber.onCompleted()
}
override fun onCancelled(error: DatabaseError?) {
subscriber.onError(FirebaseDatabaseThrowable(error))
}
}
addListenerForSingleValueEvent(valueEventListener)
}
}
fun <T>DatabaseReference.obsrveObject(clazz: Class<T>): Observable<T> {
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(clazz)
}
else {
// if clazz is nullable return null
// if clazz is not nullabel throw
throw Exception("")
}
}
}
注意:我还没有亲自使用Firebase,所以下面的一些示例可能无法编译,但应该足够接近。
Class<T>
和KClass<T>
都没有跟踪可空性,因为他们只代表一个阶级。然而,KType
可以表示“具有可选类型参数的类,加上可空性”并且具有isMarkedNullable
属性。
你可以使用reified type parameters来获得通用类型的KClass
,但你不能得到(从Kotlin 1.1开始)KType
。但是,您仍然可以检查泛型类型是否可以为空(nullable reified type : Kotlin)与null is T
(感谢sosite为pointing out,在null as T
/ try
中包装catch
不是必需的)。
有了这个,只要你可以将obsrveObject
标记为inline
,你可以“检查通用参数是否是可选的”:
inline fun <reified T> DatabaseReference.obsrveObject(): Observable<T> {
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(T::class.java)
} else if (null is T) {
null as T
} else {
throw Exception("")
}
}
}
用法:
databaseReference.obsrveObject<User>() // Observable<User>
databaseReference.obsrveObject<User?>() // Observable<User?>
如果你不能使用内联函数(以及因此具体的类型参数),那么你需要找到一种获得KType
的方法。
你可以从KType
上的returnType
获得KCallable<R>
,但你也可以使用KType
从KClass<T>
创建一个createType
:
User::class.createType(nullable = false) // User
User::class.createType(nullable = true) // User?
这里的类是类型的classifier
,所以根据你如何使用obsrveObject
,你可以将它的参数类型从Class<T>
更改为KCallable<T>
。您可以直接将其更改为KType
并根据需要创建实例但是我猜你当前从属性的返回类型抓取clazz
所以我会选择KCallable<T>
:
fun <T : Any> DatabaseReference.obsrveObject(callable: KCallable<T>): Observable<T?> {
val kType = callable.returnType
val kClass = kType.classifier as KClass<T>
val clazz = kClass.java
return observeSingleEvent().map { snapshot ->
if (snapshot != null) {
snapshot.getValue(clazz)
} else if (kType.isMarkedNullable) {
null
} else {
throw Exception("")
}
}
}
然后,您将使用对可调用(属性,函数等)的引用来调用它:
databaseReference.obsrveObject(session::user)
以上是关于Kotlin - 检查通用参数是否可选?的主要内容,如果未能解决你的问题,请参考以下文章