我正试图强迫自己在Kotlin中使用函数式编程,并尽可能避免使用可变的变量。通常,对于单元返回函数的 ad hoc 测试,我只需在函数内部println()
查看它是否正常工作。但是对于这个测试,我需要累积一个字符串,然后最终使用assertEquals(...)
。
像往常一样,我发现自己在封闭范围内宣布var
并使用+=
积累到其中。 通过传递/链接函数并消除可变变量来实现这一功能是否有更多功能?以下是一些简化但具有说明性的代码:
inline fun <T> Iterable<T>.forEachFrom(beg:Int, act:(T)->Unit) {
var i=0; if (beg>=0) for (e in this) if (i++ >= beg) act(e)
}
fun main(args:Array<String>) {
val l = listOf("zero", "one", "two", "three", "four")
// print-to-screen test
l.forEachFrom(2){print("$it-")}; println()
// output: two-three-four-
// accumulate-in-var test
var s = ""
l.forEachFrom(2){s += "$it-"}; println(s)
// output: two-three-four-
// Is there a purely functional way, without declaring a mutable var?
// val s = l.forEachFrom(2){accumulator???("$it-")}
// - OR -
// val s = l.forEachFrom(2).accumulator???("$it-")
// println(s)
}
答案 0 :(得分:3)
只使用kotlin-stdlib并保留代码的语义(即只迭代一次)的方法是convert the Iterable<T>
to Sequence<T>
并使用.drop(n)
扩展名:
inline fun <T> Iterable<T>.forEachFrom(beg: Int, act: (T) -> Unit) =
if (beg >= 0)
asSequence().drop(beg).forEach(act) else
Unit
UPD:在讨论了整体问题后,我们提出了另一种方法。
如果您有一个自定义高阶函数,它迭代项目并且只接受回调但不返回任何内容,您可以使用buildSequence { ... }
将该自定义迭代逻辑包装到Sequence<T>
中传递yield(it)
作为回调:
val sequenceFromCustomFunction = buildSequence {
l.forEachFrom(2) { yield(it) }
}
这允许您以功能样式处理此序列,特别是折叠序列:
val s = sequenceFromCustomFunction.fold("") { acc, it -> acc + it + "-" }