在 Kotlin Set 接口中调用 add 方法时未解决的引用错误

Unresolved reference error while calling add method in Kotlin Set interface

如果我使用 Set 接口引用并尝试调用 add 方法,我会收到未解决的引用错误:

  fun main(args : Array<String>) {
    val set = HashSet<Integer>()
    set.add(Integer(1)) //OK

    val seti : Set<Integer> = HashSet<Integer>()
    seti.add(Integer(2)) //FAILING: Unresolved reference to add**
  }

我不明白这种行为。 Java Set 接口有一个 add 方法,我希望 Kotlin 是一个扩展版本,并且不会有更少的方法。

PD1:我在 Idea IDE 或使用 gradle 构建时遇到了同样的错误。 PD2:使用科特林 1.0.0-beta-4584

Kotlin 将 Java 的 Set 接口分成两个接口:SetMutableSet。后一个接口声明了变异方法,例如您正在寻找的 add 方法。

通常,MutableSet 等接口扩展了 Set 接口,HashSet 等实现实现了 MutableSet 接口。然后 Set 接口可用于传递 read-only 实例,以帮助避免常见错误的发生。

关于您的代码的一些注意事项,请参阅 关于 Set 接口以及编译器错误的原因。 这个答案 纯粹是为了补充信息:

首先,您可以使用 hashSetOf() 函数代替 HashSet 构造函数,虽然使用构造函数很好,但不太常见。

val mySet = hashSetOf<Int>()

您应该使用 Int 而不是 Integer。当您没有收到编译器警告时,因为您应该让 Kotlin 决定它何时谈论原语或 类 for IntLongByte 等。做不要忽视那个警告。文档中的 table for mapped types 可能不清楚它适用于同一类型的原始版本和盒装版本,除非您需要原始数组,否则不要担心正在使用哪个。

不要实例化Integer 类 例如代码调用Integer(1)Int(1)。相反,使用类似于以下代码的代码——它让 Kotlin 为您进行装箱:

val mySet1 = hashSetOf(1, 2, 3) // makes a HashSet<Int> which in Java is HashSet<Integer>

val mySet2 = hashSetOf<Int>()   // makes a HashSet<Int> which in Java is HashSet<Integer>
mySet2.add(1)
mySet2.add(2)
mySet2.add(3)

如果你想初始化一个集合,同时将集合的构建包装到构造中并返回只读接口,那么你有很多选择。其中一些是:

val mySet: Set<Int> = hashSetOf<Int>().apply  {
    // do logic that adds to set (`this` is the set)
} 

或:

val mySet: Set<Int> = run  {
    val tempSet = hashSetOf<Int>()
    // do logic that adds to set
    tempSet
}

或:

val mySet = someFunc()

fun someFunc(): Set<Int> {
   val tempSet = hashSetOf<Int>()
   // do logic that adds to set
   return tempSet
}

查看函数文档:apply(), let(), run(), and with()

我自己的库中有一个相当无用的扩展函数,当我需要一个只读接口时它会很清楚,因为转换会产生警告,而且我并不总是想在声明中指定冗余类型。为了可读性,它是一个扩展:

@Suppress("USELESS_CAST")
fun <T: Any> MutableSet<T>.readonly(): Set<T> = this as Set<T>

用法是:

val mySet = hashSetOf<Int>().apply {
    // logic that builds the set
}.readonly() 

// inferred type of mySet is Set<Int>