Как работает in в циклах и проверках?
В языке Kotlin ключевое слово in используется в двух основных контекстах:
- При **итерации в циклах
** - При проверке принадлежности элемента коллекции, диапазону или промежутку значений
1. in в циклах for
Оператор in позволяет перебирать элементы коллекций, массивов, диапазонов и любых объектов, реализующих интерфейс Iterable или предоставляющих функцию iterator().
Примеры:
val list = listOf("a", "b", "c")
for (item in list) {
println(item)
}
Здесь item in list означает, что переменная item последовательно принимает значения из списка.
Также можно использовать с диапазонами чисел:
for (i in 1..5) {
println(i)
}
Дополнительно существуют формы:
-
until: исключает верхнюю границу
for (i in 1 until 5) → 1, 2, 3, 4 -
step: задаёт шаг итерации
for (i in 1..10 step 2) → 1, 3, 5, 7, 9 -
downTo: обратный порядок
for (i in 5 downTo 1) → 5, 4, 3, 2, 1
Цикл for (x in collection) трансформируется компилятором в вызовы:
val iterator = collection.iterator()
while (iterator.hasNext()) {
val x = iterator.next()
...
}
2. in в проверках if, when, выражениях
Оператор in может использоваться для проверки, содержится ли элемент в диапазоне (IntRange), коллекции (List, Set, Map.keys) или массиве (Array).
Примеры с диапазоном:
val x = 5
if (x in 1..10) {
println("x попадает в диапазон от 1 до 10")
}
Проверка на отсутствие:
if (x !in 10..20) {
println("x не входит в диапазон 10..20")
}
Примеры с коллекцией:
val names = listOf("Alice", "Bob", "Charlie")
if ("Bob" in names) {
println("Bob найден в списке")
}
Работает через вызов contains():
element in collection компилируется как collection.contains(element)
С when:
when (x) {
in 1..5 -> println("x в первой половине десятка")
in 6..10 -> println("x во второй половине десятка")
!in 1..10 -> println("x вне диапазона 1..10")
}
Как in работает под капотом
Оператор in не является оператором в классическом понимании. Это синтаксический сахар, который Kotlin превращает в вызовы определённых функций:
-
in collection → collection.contains(element)
-
in range → range.contains(value)
-
for (x in iterable) → iterable.iterator() + hasNext() + next()
Для кастомных классов можно переопределить поведение in, реализовав метод operator fun contains(...):
class Box(val items: List<String>) {
operator fun contains(item: String): Boolean {
return items.contains(item)
}
}
val box = Box(listOf("apple", "banana"))
if ("banana" in box) {
println("Есть банан")
}
Где ещё in может использоваться
- Фильтрация в when:
val grade = 'A'
when (grade) {
in 'A'..'C' -> println("Хорошо")
in 'D'..'F' -> println("Плохо")
else -> println("Неизвестно")
}
- В DSL (Domain Specific Language) конструкциях:
Некоторые библиотеки или фреймворки могут использовать in для выражения логики включения, если правильно перегрузить contains.
Различия in и аналогов в Java
В Java нет оператора in. Вместо x in list приходится писать list.contains(x). Для циклов по коллекциям Java использует for-each:
for (String s : list) { ... }
Kotlin делает API выразительнее и безопаснее, сокращая шаблонный код, а оператор in обеспечивает более декларативный и читаемый стиль.