在Kotlin中链接对象的更简单或更实用的方法

Kev*_*ain 7 kotlin

我已经创建了一个辅助方法buildChain,它实际上创建了一个对象链,因为它们实现了接口IChain<T> 并设置了契约next成员

代码

interface Chain<T> {
    var next: T?

    operator fun plus(next: T): T?
}

fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
    var next: T? = null
    members.forEachIndexed { i, t ->
        if (i == 0) {
            next = first + t
        } else {
            next = next?.run { this + t }
        }
    }
    return first
}
Run Code Online (Sandbox Code Playgroud)

实施例

data class Person(val name: String) : Chain<Person> {
    override var next: Person? = null

    override fun plus(next: Person): Person? {
        this.next = next
        return next
    }
}

fun createPersonChain()
        = buildChain(Person("Bob"), Person("Bitzy"), Person("Blitzy"))
Run Code Online (Sandbox Code Playgroud)

实现输出示例

@JvmStatic fun main(args: Array<String>) {
    var first = createPersonChain()
    // first.name = "Bob"
    // first.next.name = "Bitzy"
    // first.next.next.name = "Blitzy"
 }
Run Code Online (Sandbox Code Playgroud)

是否有一个functionalsimpler用于acheiving的方式code上面保持implementaion用法一样吗?

hot*_*key 9

功能性成语折叠很适合您的需求:它采用初始项目,然后迭代其他项目,保持累积值,使用您提供的功能更新每个正在处理的项目.

在科特林,它是fold扩展功能Iterable,SequenceArray.

您可以通过以下方式使用它:

fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
    members.fold(first as T?) { acc, i -> acc?.let { it + i } }
    return first
}
Run Code Online (Sandbox Code Playgroud)

这里first as T?需要使用强制转换类型来推断为可为空T?,因为plus在你的Chain<T>返回可以为空的值(顺便说一句,是否有必要?).

您也可以使用foldRight,它只是以相反的顺序迭代:

fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
        (listOf(first) + members)
            .foldRight(null as T?) { i, acc -> acc?.let { i + acc }; i }
Run Code Online (Sandbox Code Playgroud)

而且有reducereduceRight类似的语义,但是使用第一和最后一个项目分别累加器的初始值.这是以下示例reduceRight:

fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
        (listOf(first) + members).reduceRight { i, acc -> i.apply { plus(acc) } }
Run Code Online (Sandbox Code Playgroud)