如何在 Kotlin 中构建功能代码?

Mes*_*yah 3 functional-programming kotlin

我想知道在 Kotlin 中构建函数式代码的最佳方式是什么。

我不想创建不必要的对象(并将函数放在封闭的范围内)来对我的函数进行分组。我听说我可以按包对函数进行分组并将它们放在包的顶层。我还在 Arrow 库中看到函数作为扩展函数分组在接口伴随对象中,这看起来是最好的,除了我需要创建一个伴随对象。

对象方式:

object Container {
    fun myFunc() = ...
}

...

Container.myFunc()
Run Code Online (Sandbox Code Playgroud)

包装方式:

package myPackage

fun myFunc() = ...

...

myPackage.myFunc()
Run Code Online (Sandbox Code Playgroud)

箭头方式:

interface Container {
    companion object {
        fun Container.myfunc() = ...
    }
}

...

Container.myFunc()
Run Code Online (Sandbox Code Playgroud)

使用 Kotlin 构建我的函数并对其进行分组的最佳方法是什么?我想保持纯函数式风格,避免创建任何类型的对象,并且能够通过命名空间轻松导航到函数,例如:

Person.Repository.getById(id: UUID)

The*_*tor 5

如果我理解正确,您正在寻找名称空间的概念(用于访问符号的结构化层次范围)。

Kotlin 不支持命名空间,但正如您所发现的,有不同的方式来实现类似的功能:

  1. object声明。它们几乎满足了需求,但是它们会导致在 JVM 中创建一个实际对象并引入一种您不需要的新类型。Jetbrains 团队通常不鼓励使用对象作为命名空间,但它当然仍然是一种选择。我没有看到接口内的伴随对象如何增加任何价值。也许这个想法是将范围限制为实现接口的类。

  2. 顶级功能。尽管可能,Kotlin 中的顶级函数会污染全局命名空间,并且调用站点不允许您指定它们所属的位置。你当然可以做变通方法,但所有这些都相当丑陋:

    • 完全合格的包裹 com.acme.project.myFunc()
    • 使用故意简短但不再代表域的包 functional.myFunc()
    • 不带包但带前缀的调用函数 package_myFunc()
  3. 扩展功能。如果功能与其操作的对象密切相关,那么扩展函数是一个不错的选择。你看这对科特林标准集合和他们所有的功能算法,如map()filter()fold()等。

  4. 全局变量。这不会增加太多object方法,只会阻止您引入命名类型。这个想法是创建一个实现一个或多个接口的任意对象(不幸的是,没有接口,声明的函数不能全局访问):

    interface Functionals {
        fun func(): Int
    }
    
    val globals = object : Functionals {
        override fun func() = 3
    }
    
    Run Code Online (Sandbox Code Playgroud)

    如果您的对象实现不同的接口,这主要是方便的,这样您就可以只将部分功能传递给不同的模块。请注意,object单独使用s也可以实现相同的效果,因为它们也可以实现接口。