8

Kotlin 允许命名一个与现有类相同的函数,例如HashSet使用初始化函数可以这样实现:

fun <T> HashSet(n : Int, fn: (Int) -> T) = HashSet<T>(n).apply {
    repeat(n) {
        add(fn(it))
    }
}

使用时,它看起来像一个普通的HashSet构造函数:

var real = HashSet<String>()
var fake = HashSet(5) { "Element $it" }

是否应该避免或鼓励这样做,为什么?

4

2 回答 2

15

UPD

在更新的编码约定中,有一个关于这个主题的部分

工厂功能

如果你为一个类声明一个工厂函数,避免给它与类本身相同的名字。更喜欢使用不同的名称,以明确为什么工厂函数的行为是特殊的。只有在真的没有特殊语义的情况下,才可以使用与类相同的名称。

例子:

class Point(val x: Double, val y: Double) {
    companion object {
        fun fromPolar(angle: Double, radius: Double) = Point(...)
    }
}

不过,我在下面描述的动机似乎仍然成立。


如有关命名样式的文档中所述:

如果有疑问,默认使用 Java 编码约定,例如:

  • 方法和属性以小写开头

避免将函数命名为与类相同的一个重要原因是,它可能会使以后使用它的开发人员感到困惑,因为与他们的期望相反:

  • 该函数将不可用于超级构造函数调用(如果类是open
  • 它不会通过反射作为构造函数可见
  • 它不能用作 Java 代码中的构造函数(new HashSet(n, it -> "Element " + it)是一个错误)
  • 如果您想稍后更改实现并返回一些子类实例,那么它将变得更加混乱,HashSet(n) { "Element $it" }它将构造不是 aHashSet而是例如 aLinkedHashSet

最好明确地表明它是一个工厂函数,而不是构造函数,以避免这种混淆。

在 stdlib 中通常也避免将函数命名为与类相同。给定SomeClass,在 stdlib 中,工厂函数的首选命名样式是someClassOfsomeClassBy或者任何最能解释函数语义的名称。示例:

  • generateSequence { ... }sequenceOf(...)
  • lazy { ... }lazyOf(...)
  • compareBy { ... }
  • listOf(...), setOf(...),mapOf(...)

因此,绝对应该有充分的理由让函数模仿构造函数。

相反,函数的名称可能会告诉用户更多(甚至是所有内容)它的用法。

于 2016-01-12T19:28:37.770 回答
-2

我同意+热键。在这种情况下,最好避免混淆。

但是,如果它仅在内部使用并且所有其他开发人员(如果有的话)都可以接受,我会说去做。Python 承认这个想法,我喜欢它。哎呀,它们是双向的,如果你感觉它更像是一个函数,那么你也可以在函数案例中命名一个类。但是,Python 不必处理 Java 互操作,因此绝对不要为公共代码这样做。

于 2016-01-13T12:14:21.057 回答