为什么我在Kotlin中使用原始的parseList函数时得不到正确的结果?

我正在学习有关Android开发人员Kotlin的Anko示例代码(本书) https://github.com/antoniolg/Kotlin-for-Android-Developers

方法1来自示例代码并覆盖parseList,但是很难理解。

所以我尝试使用方法2而不是方法1,方法2使用原始parseList函数,但是当我使用方法2时,我得到空白记录,我在方法2中做了什么错误

class DayForecast(var map: MutableMap<String, Any?>) { var _id: Long by map var date: Long by map var description: String by map var high: Int by map var low: Int by map var iconUrl: String by map var cityId: Long by map constructor(date: Long, description: String, high: Int, low: Int, iconUrl: String, cityId: Long) : this(HashMap()) { this.date = date this.description = description this.high = high this.low = low this.iconUrl = iconUrl this.cityId = cityId } } 

方法1

 override fun requestForecastByZipCode(zipCode: Long, date: Long) = forecastDbHelper.use { val dailyRequest = "${DayForecastTable.CITY_ID} = ? AND ${DayForecastTable.DATE} >= ?" val dailyForecast = select(DayForecastTable.NAME) .whereSimple(dailyRequest, zipCode.toString(), date.toString()) .parseList { DayForecast(HashMap(it)) } /* common code block */ } fun <T : Any> SelectQueryBuilder.parseList(parser: (Map<String, Any?>) -> T): List<T> = parseList(object : MapRowParser<T> { override fun parseRow(columns: Map<String, Any?>): T = parser(columns) }) 

方法2

 override fun requestForecastByZipCode(zipCode: Long, date: Long) = forecastDbHelper.use { val dailyRequest = "${DayForecastTable.CITY_ID} = ? AND ${DayForecastTable.DATE} >= ?" val dailyForecast = select(DayForecastTable.NAME) .whereSimple(dailyRequest, zipCode.toString(), date.toString()) .exec { parseList(classParser<DayForecast>()) } /* common code block */ } 

我真的认为你应该坚持使用'方法1'的方法,一旦你意识到Kotlin让你做什么,就会容易得多。 因为我不知道你对Kotlin有多少了解,所以我会尽量完整地说明这一点。

现有的类SelectQueryBuilder有(我推测)一个名为parseList的函数,现有的函数需要一个MapRowParser<T>MapRowParser<T>有一个函数parseRow ,它接受一个Map<String, Any?>并返回一个T

在旧的Java工作方式中,您将从MapRowParser<T>派生,并将重写parseRow以便它执行所需的转换; 将Map<String, Any?>转换成DayForecast (泛型T现在有一个类型)。 这个派生类的一个实例被传递到现有的parseList函数中。 你的派生类看起来像

 class MapToDayForecastRowParser extends MapRowParser<DayForecast> { @Override public DayForecast parseRow(Map<String, Object> map) { // Note that Java's "Object" is more or less Kotlin's "Any?" return new DayForecast(map); // Might need to convert the map type btw } } 

这个扩展方法使得包装/隐藏/抽象派生类的创建变得非常简单。 扩展方法需要一个lambda表达式,也就是说,你必须解析新的parseList方法一个代码块,它接受一个Map<String, Any?>并返回T (这就是DayForecast(HashMap(it))所做的事情, it是一个自动命名的变量,它是Map ,然后扩展方法调用现有的parseList方法,解析它自己创建的匿名类,这意味着使用这个扩展方法创建一个新的匿名类,但是Kotlin编译器处理得很好。

起初让我迷惑的一个部分就是Kotlin处理匿名课程的方式。

 // Java new MapRowParser<T>() { @Override public T parseRow(Map<String, Object>) { /* Map to T logic */ } } // Kotlin object : MapRowParser<T> { override fun parseRow(columns: Map<String, Any?>): T = parser(columns) } 

Kotlin也使得处理'lambda'非常容易。 它被解析成parser的扩展方法,然后设置为我们的匿名类parseRow函数的实现。 如果你愿意,你也可以重用它们,如果你需要在很多地方进行相同的解析,你可以使用一个命名函数。

这种新的Kotlin方式的巨大优势在于,它非常容易专注于你想要做的事情。 有了这个扩展方法,可以很快的重复使用它,以便在另一个查询中可以执行parseList{ it.getOrDefault("name", "unkown_user") } 。 你现在可以轻松地思考:“如果每一行都是一张地图,那么我怎么把它转换成我想要的值?”。