Kotlin разрушает более пяти компонентов - PullRequest
2 голосов
/ 28 апреля 2019

У меня есть результат регулярного выражения, которое возвращает семь групп захвата в массив.

Вместо того, чтобы использовать нижний индекс элементов массива для создания моего объекта, я думал, что буду использовать деструктуризацию, проблема в том, чтоУ меня может быть только пять компонентов.

Минимальный пример:

//  val (a, b, c, d, e) = listOf(1, 2, 3, 4, 5)
val (a, b, c, d, e, f, g) = listOf(1, 2, 3, 4, 5, 6, 7)

Выход компилятора:

> Error:(70, 41) Kotlin: Destructuring declaration initializer of type
> List<Int> must have a 'component6()' function 
> Error:(70, 41) Kotlin: Destructuring declaration initializer of type 
> List<Int> must have a 'component7()' function

Есть ли способ иметь более пяти компонентов илиэто макс?

Ответы [ 2 ]

4 голосов
/ 28 апреля 2019

Для интерфейса List (в качестве функций расширения) определены только 5 компонентных функций.

Вы можете добавить свои собственные функции компонентов в качестве функций расширения:

operator fun <T> List<T>.component6() = this[5]
operator fun <T> List<T>.component7() = this[6]
// ...

Это будетработать сейчас:

val (a, b, c, d, e, f, g) = listOf(1, 2, 3, 4, 5, 6, 7)

Из документов :

И, конечно, могут быть component3 () и component4 () и так далее.

Обратите внимание, что функции componentN () должны быть помечены ключевым словом оператора, чтобы их можно было использовать в объявлении деструктурирования.

3 голосов
/ 28 апреля 2019

Котлин определяет методы расширения для этих деструкторов компонентов. В отличие от классов данных, они не генерируются бесконечно по одному для каждого элемента. Это также делает их немного опасными, к которым я вернусь позже.

Для справки, определение здесь , а KDoc можно найти здесь (поиск по component в списке. Для легкого доступа, здесь component1 ).

Как вы можете видеть в определении источника (и документации по этому вопросу, но источник делает его более заметным), есть только 5 методов (component1 до component5), каждый из которых вызывает get(n - 1), где n - идентификатор деструктора компонента.

Если вы хотите больше, вам придется определить их самостоятельно, в виде:

inline operator fun <T> List<T>.componentN(): T {
    return get(N - 1)
}

(или в стиле, предложенном в другой ответ - они дают одинаковые результаты.)

И снова, где N равно 6 и выше, соответствует количеству предметов, которые вы планируете иметь.

Однако я бы не рекомендовал это. Намного легче перебирать его с помощью цикла for, и он также менее подвержен ошибкам. Возьмите для примера это:

val (a, b, c, d, e) = listOf(1, 2, 3, 4)

Это вызовет исключение ArrayIndexOutOfBoundsException. Однако, если у вас есть статический список (и вы знаете, что делаете), уничтожение с помощью componentN безопасно. Хотя, если у вас есть в основном статический список, в котором вы хотите использовать гибкость в будущем, вы можете использовать класс данных. Они также генерируют для вас функции componentN и ограничивают количество полей, которые у вас есть, что означает отсутствие исключений во время выполнения, но вместо этого ошибки компилятора.

Если вы используете списки для включения итерации в дополнение к уничтожению, вы также можете воспользоваться альтернативным подходом, определить operator fun iterator и вернуть список элементов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...