Ответ 1
Ответ таков: потому что они решили удалить его. Вы все равно можете использовать этот синтаксис:
for (a in 1..10) print("$a ") // >>> 1 2 3 4 5 6 7 8 9 10
for (a in 10 downTo 1 step 2) print("$a ") // >>> 10 8 6 4 2
Я все еще думаю, что "традиционный" способ использования цикла for очень эффективен с полным контролем индекса. Почему он был удален в Котлин?
что я должен делать в kotlin со следующим кодом java
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
....
Ответ таков: потому что они решили удалить его. Вы все равно можете использовать этот синтаксис:
for (a in 1..10) print("$a ") // >>> 1 2 3 4 5 6 7 8 9 10
for (a in 10 downTo 1 step 2) print("$a ") // >>> 10 8 6 4 2
Он не был "удален". Дизайн нового языка не начинается с набора функций любого существующего языка; мы начинаем с языка, который не имеет никаких функций, и начинаем добавлять функции, которые необходимы, чтобы выразить определенное поведение красивым и идиоматическим способом. До сих пор мы не знаем о каком-либо поведении, для которого цикл "для" C-стиля был бы самым приятным и самым идиоматичным способом его выражения.
Я думаю, что причина, по которой они сделали это таким образом ("не удалено"), заключается в том, что они хотели сделать Kotlin более выразительным.
Например, в Java мы можем создать цикл for следующим образом:
for(int x = 1; x <= 10; x++) {
System.out.print(x);
}
Все, что вы пытаетесь сделать, это то, что вы хотите распечатать значения от 1 до 10, вот и все. Поэтому Котлин решил перевести ваши слова в код и убрать ненужные подробности.
for (x in 1..10) print("$x")
Еще один полезный способ сохранить эти индексы в белых итерациях (то есть, Iterable) - это использовать метод withIndex()
. Например:
for((i, element) in myIterable.withIndex()){
//do something with your element and the now known index, i
}
Это, как я заметил, достигает того же, что предложено в этом ответе, но я думаю, что было бы лучше, если бы мы использовали уже встроенный метод Iterables для таких ситуаций вместо того, чтобы реализовывать их снова. Мы можем сказать, что это также похоже на forEachIndexed{}
:
myIterable.forEachIndexed{i, element ->
//do something here as well
}
Он не был удален. Это просто другой синтаксис для него. Эквивалент кода Java:
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
Было бы написано в Котлин таким образом:
val n = 10
for (i in 0..n-2) {
for (j in i+1..n-1) {
println("I'm low level for loop! I just look more friendly.")
}
}
Kotlin использует диапазоны для определения итераторов циклов ради краткости кода.
Там нет необходимости использовать традиционный for
цикла в Котлин, потому что вы можете с помощью Котлин лямбды, чтобы делает ваш код более выразительным и читаемым. например:
arrayOf(1, 2, 3).forEachIndexed { index, item -> /**TODO**/}
Kotlin поддерживает только каждый цикл, для каждого цикла принимает любой Iterable
s/Array
s/type имеет оператор iterator
.
Если вы хотите вернуться к использованию выражения для каждого цикла, вы можете написать код, как показано ниже, и вы можете видеть, что для каждого цикла требуется больше кода, чем lamda, поэтому stream api & функциональный интерфейс был введен в [ TG00]:
val array = arrayOf(1, 2, 3)
for(index in array.indices){
val item = array[index]
// todo
}
Если вам нужно вернуться к традиционным for
цикла Вы можете с помощью repeat
вместо этого, например:
repeat(5){index-> /**TODO**/}
Зачем? "Традиционный" цикл является причиной исключения "index out of bounds" в отличие от цикла для элементов коллекции.
Вы можете создать собственную функцию для реализации "традиционной циклы с полным контролем индекса". Или нетрадиционным. Например, гибрид forEachIndexed()
, with()
, count()
с индексом 1 для подсчета.
inline fun <T> Iterable<T>.forWithIndexed1(action: T.(index: Int) -> Unit): Int {
var index = 0
for (item in this) item.action(++index)
return index
}
Это не имеет никакого смысла, потому что иногда вы хотите иметь больше пользовательских циклов с пользовательскими шагами, и такая структура удаляет их из логики
var array = ["-m", "/test/app", "-w", "us"];
for (var i = 0; i < array.length; i += 2) {
console.log("option =" + array[i]);
console.log("value =" + array[i+1])
}
Kotlin пытается обеспечить беглую итерацию, которая охватывает подавляющее большинство циклических конструкций. Тем не менее, мне был нужен традиционный цикл for (например, java) с немедленно завершающейся областью состояния, условием выхода, которое оценивается перед выполнением тела цикла, и операцией после выполнения (мой вариант использования был сложным: мне нужно было повторить с использованием динамического выхода условие, основанное на процедуре сжатия и степени 2). Я придумал эти общие функции:
fun <S> forloop(state: S, condition: (s: S) -> Boolean, postExecution: (s: S) -> Unit, block: (s: S) -> Unit) {
while (condition(state)) {
block(state)
postExecution(state)
}
}
data class SingleIndex(var i: Int)
fun forloop(i: Int, condition: (s: SingleIndex) -> Boolean, postExecution: (s: SingleIndex) -> Unit, block: (s: SingleIndex) -> Unit) {
forloop(SingleIndex(i), condition, postExecution, block)
}
Примеры здесь:
fun main() {
forloop(0, {it.i < 10}, {++it.i}) {
println("forloop test: i=${it.i}")
}
data class State(var i: Int, var j: Int)
forloop(State(0, 1), {it.i < 10}, {++it.i; it.j += it.i}) {
println("forloop test: i=${it.i}, j=${it.j}")
}
}
Хотя, в соответствии с философией языка, вы должны использовать это только в редких случаях.
Для этого точного случая можно использовать следующую двойную петлю:
for (i in 0 until n) {
for (j in (i + 1) .. n) {
for (i in generateSequence(0) { it + 2 }.takeWhile { it < array.length }) {
// do something useful
}
generateSequence(0) { it + 2 }.takeWhile { it < array.length }.forEach {
// Do something useful
}