【问题标题】:builder syntax for collections in KotlinKotlin 中集合的构建器语法
【发布时间】:2018-02-27 03:17:01
【问题描述】:

我在 Kotlin 上启动并希望以构建器语法的模式配置 ArrayLabels。我提出了 Kotlin 标准库函数 (apply) 与集合上的辅助函数 (forEach)。将其称为构建器模式是否正确?这对我来说意味着声明、分配和配置是在一行/一步中完成的。我很欣赏任何关于如何以更紧凑和清晰的“Kotlin-ish”方式编写它的想法,或者这或多或少是首选的 Kotlin 语法。顺便说一句,有很多方法可以弄错(使用let 而不是apply 不会返回接收者)。

val labels = arrayOf(Label("A"),Label("B"),Label("C"),Label("D")).apply {
    this.forEach { it.prefWidth = 50.0 }
}

【问题讨论】:

  • 在我看来,您正在做的是对这些功能的完美利用。

标签: collections kotlin builder


【解决方案1】:

我的建议是避免在你的成语中重复 Label 这个词:

val labels = arrayOf("A", "B", "C", "D")
        .map { Label(it).apply { prefWidth = 50.0 } }
        .toTypedArray()

这会创建更多瞬态对象,但它会减少噪音并更容易看到标签之间变化的东西。

【讨论】:

  • 是的,我同意。目的是从Array<String> 创建Array<Label>,然后统一修改宽度参数。如果我在所有情况下都坚持List,我想这会消除这个答案的最后一行,或者更好的是,允许.onEach。但是,我后来使用了仅适用于数组的扩展运算符。
【解决方案2】:

您可以使用带有内部applymap,而不是显式的forEach,这已在原帖中正确选择:

arrayOf(Label("A"), Label("B"), Label("C"), Label("D"))
    .map { it.apply { prefWidth = 50.0 } }

在这些情况下使用apply 是完全有效的,甚至可以定义为成语 here (Builder-style usage of methods that return Unit)

显示的代码在我看来更具可读性,尽管它在map 中创建了数组的副本。在内存/性能严重的情况下,您可能不想付出这个代价,而是使用您已经建议的解决方案。


作为另一种选择,如果您的代码库中经常需要此类操作,这可能会很有用,一个简单的扩展函数会有所帮助:

inline fun <T> Array<T>.applyEach(action: T.() -> Unit) = apply { forEach { it.action() } }

//usage
val labels = arrayOf(Label("A"), Label("B"), Label("C"), Label("D")).applyEach { prefWidth = 50.0 }

【讨论】:

  • map() 的问题是它会创建原始数组的副本。虽然当数组有 4 个元素时这不是一个真正的问题,但它不会缩放。 forEach() 只会遍历原始数组并对每个元素应用一个块。
  • 它不会扩展?来吧,在这种情况下这是令人毛骨悚然的
  • 不幸的是,它没有在 Array 上定义,它也需要一个普通的 lambda,即你需要使用 it.prefWidth=50.0
  • 对于第一个答案,地图返回 List 而不是 Array。所以你需要包含.toTypedArray()。也太糟糕了onEach 不适用于Array。 @s1m0nw1 有扩展函数的想法,如果标准库函数不能解决问题,自己创建。我喜欢这样。
【解决方案3】:

Standard.kt 中的函数确实令人困惑,但您正确使用了apply():它最好在初始化变量时应用。您完全可以将其称为 Builder 模式,因为它为构造类的实例提供了一种简洁的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多