我们应该避免命名一个与 Kotlin 中现有的 class 相同的函数吗?为什么?

Should we avoid naming a function same as an existing class in Kotlin? Why?

Kotlin 允许命名一个与现有 class 相同的函数,例如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" }

应该避免还是鼓励这种情况,为什么?

UPD

在更新的编码约定中,有 section on this topic:

Factory functions

If you declare a factory function for a class, avoid giving it the same name as the class itself. Prefer using a distinct name making it clear why the behavior of the factory function is special. Only if there is really no special semantics, you can use the same name as the class.

Example:

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

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


如有关 naming style 的文档中所述:

If in doubt default to the Java Coding Conventions such as:

  • methods and properties start with lower case

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

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

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

在 stdlib 中通常也避免将函数命名为 class。给定 SomeClass,在 stdlib 中,工厂函数的首选命名风格是 someClassOfsomeClassBy 或任何能最好地解释函数语义的命名风格。例子:

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

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

相反,函数的名称可能会告诉用户有关其用法的更多信息(甚至是所有信息)。

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

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