如何在不使用 Monkeypatching 的情况下使用迭代器在 Kotlin 中扩展 JSONArray class?

How can I extend the JSONArray class in Kotlin with an iterator, without using Monkeypatching?

我在我的代码中经常使用 JSONArray class,有时我会通过提供一个字符串来创建一个新的。

我发现 可以通过“monkeypatching”向 class 添加所需的功能,但我不允许这样做。

所以我决定创建一个自定义 class 来扩展 JSONArray 并添加此方法。但是,我 运行 遇到了构造函数的问题,我已经解决了如下问题:

class JSONArray(s : String? = null) : JSONArray(), Iterable<JSONObject>  {
    init {
        if(s == null) {
            JSONArray()
        } else {
            JSONArray(s)
        }
    }

    override fun iterator(): Iterator<JSONObject> {
        return (0 until length()).asSequence().map { get(it) as JSONObject }.iterator()
    }
}

我对 init 的外观不满意。有更好的方法吗?

如果您绝对不想定义扩展函数(我认为这将是解决您问题的最佳方法),您可以通过提供 2 个构造函数(一个用于超级class):

class MyJSONArray : JSONArray, Iterable<JSONObject> {
    constructor(): super()

    constructor(x: String): super(x)

    override operator fun iterator(): Iterator<JSONObject> {
        return (0 until length()).asSequence().map { get(it) as JSONObject }.iterator()
    }
}

然后你可以创建一个有或没有给定字符串的实例,但你必须选择正确的构造函数。如果您需要一个根据可空值使用正确构造函数的函数,那么可以这样做:

class MyJSONArray : JSONArray, Iterable<JSONObject> {
    ...
    companion object {
        fun of(x: String?) = if(x == null) MyJSONArray() else MyJSONArray(x)
    }
}

然后你可以编写 MyJSONArray.of(nullableString) 来创建一个带或不带字符串的 JSONArray,而不需要调用不同的构造函数。


自己的子 class 的一大缺点是您不能像使用自己创建的代码一样从自己的代码库外部使用 JSONArray

另一种不创建子 class 的解决方案是引入辅助函数,在不扩展它的情况下为您提供 JSONArray 的迭代器:

fun iteratorOf(jsonArray: JSONArray): Iterator<JSONObject> =
    (0 until jsonArray.length()).asSequence().map { jsonArray.get(it) as JSONObject }.iterator()

为了使用这个函数从JSONArray中获取一个iterable,我们可以定义如下函数:

fun iterableOf(jsonArray: JSONArray) = Iterable { iteratorOf(jsonArray) }

然后您可以遍历任何 JSONArray,例如iterableOf(jsonArray).forEach{ ... }.