Неопределенная ошибка ссылки при вызове метода add в интерфейсе Kotlin Set

Если я использую ссылку на интерфейс 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 имеет метод добавления, и я ожидал, что Kotlin будет расширенной версией и не будет иметь меньше методов.

PD1: Я получаю ту же ошибку в Idea IDE или строю с градиентом. PD2: использование kotlin 1.0.0-beta-4584

Kotlin MutableSet интерфейс Java на два интерфейса: Set и MutableSet . Последний интерфейс объявляет мутирующие методы, такие как метод add который вы ищете.

Как правило, интерфейсы, такие как MutableSet расширяют интерфейс Set , а реализации, подобные HashSet реализуют интерфейс MutableSet . Затем интерфейс Set можно использовать для передачи экземпляра только для чтения, чтобы избежать случайных ошибок.

Несколько заметок о вашем коде, см . Ответ @ nhaarman о интерфейсе Set и почему у вас ошибка компилятора. Этот ответ предназначен исключительно для дополнительной информации:

Во-первых, вы можете использовать hashSetOf() вместо конструктора HashSet , хотя использование конструктора в порядке, это просто реже.

 val mySet = hashSetOf<Int>() 

Вы должны использовать Int вместо Integer . Вы получили предупреждение компилятора, когда вы этого не сделали, потому что вы должны позволить Kotlin решить, когда речь идет о примитивах или классах для Int , Long , Byte и т. Д. Не игнорируйте это предупреждение. Возможно, таблица для отображаемых типов в документации не ясна, что она применяется к примитивной и коробчатой ​​версии того же типа, и если вам не нужны примитивные массивы, не беспокойтесь о том, что используется.

Не создавайте экземпляры классов 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) 

И если вы хотите инициализировать набор, обертывая построение набора в конструкцию и возвращая интерфейс readonly, у вас есть много вариантов. Некоторые из них:

 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 () и с ()

У меня есть довольно бесполезная функция расширения в моих собственных библиотеках, которая дает понять, когда я хочу интерфейс для чтения, поскольку при создании кастования выдается предупреждение, и я не всегда хочу указывать избыточный тип в объявлении. Это расширение для удобства чтения:

 @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>