我正在编写这个通用方法来从firebase获取数据?在某些情况下,返回null是有效的,在其他情况下不是,是否可以检查通用参数是否可以为空?
离
reference.obsrveObject(User.class)
如果为null则抛出
reference.obsrveObject(User?.class)
应该使用空值
调用onNextfun 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("")
}
}
}
答案 0 :(得分:4)
注意:我还没有亲自使用Firebase,所以下面的一些示例可能无法编译,但应该足够接近。
Class<T>
和KClass<T>
都没有跟踪可空性,因为它们只代表一个类。但是,KType
可以表示“具有可选类型参数的类,加上可为空性”,并且具有isMarkedNullable
属性。
您可以使用reified type parameters获取通用类型的KClass
,但是您无法获得(从Kotlin 1.1开始)KType
。但是,您仍然可以检查泛型类型是否可以为null is T
与null as T
一样(感谢nullable reified type : Kotlin sosite将try
包裹在catch
中<{1}} / 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
,但您也可以使用pointing out从KClass<T>
创建User::class.createType(nullable = false) // User
User::class.createType(nullable = true) // User?
:
obsrveObject
此处的类型类型为createType
,因此根据您使用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)
然后,您将使用对可调用(属性,函数等)的引用来调用它:
function parseChart($str){
$lines = explode(PHP_EOL,$str); // split lines into array
$line_count = count($lines);
$current_label = null;
$current_object = null;
$data = array(); // output data
for($i=0;$i<$line_count;$i++){
$line = trim($lines[$i]); // remove spaces & tabs from start and end of the current line
if(strpos($line, '[')===0){ // if line starts with [
$current_label = substr($line,1,-1); // set current label
}else if(strpos($line, '{')===0){ // if line starts with {
$current_object = array(); // create new object
}else if(strpos($line, '}')===0){ // if line starts with }
if(isset($current_label))
$data[$current_label] = $current_object; // write out new object into the outpdata with the label that has been set beforehand
}else{
$equals_index = strpos($line, '='); // get index of =
if($equals_index!==false || !isset($current_object)){ // no = found or no label set -> ignore line
$key = trim(substr($line,0,$equals_index));
$value = trim(substr($line,$equals_index+1));
$current_object[$key] = $value;
}
}
}
return $data;
}