Swift 2 - Использовать регистр для использования break on if statement?

В руководстве Swift 2 упоминается, что вы можете завершить выполнение программы if. Я лично никогда не использовал break с if-statement.

Оператор break завершает выполнение программы цикла, оператора if, или оператор switch... Когда за оператором break имя метки оператора, завершает выполнение цикла цикла, если оператора или оператора switch, указанного этой меткой.

В какой ситуации можно было бы использовать break в if-statement? Эта языковая функция кажется бесполезной.

TEST:
if (true) {
    break TEST
}

Ответ 1

Использование break с инструкцией if кажется немного ухищренным, и я не могу придумать, где стиль потребует его. Тем не менее, он сохраняет дополнительный уровень отступа при пропуске последней части оператора if в предложении if-else, что может быть полезно для глубоко вложенных циклов.

В других языках популярной (и/или противоречивой) идиомой является использование меток для обработки ошибок в глубоко вложенных функциях. Например, можно было бы вырваться из цикла при ошибке, например:

func testBreak3() {
    // doesn't compile!!!
    let a = false, b = true, x = 10, y = 20, err = true
    if !a {
        if b && x > 0 {
            if y < 100 {
                if err {
                    break handleError
                }
                // some statements
            } else {
                // other stuff
            }

        }
    }
    return  // avoid error handling

    handleError:
    print("error")
    // handle the error
}

Но в Swift (я использую 2.0 в качестве ссылки) метки отличаются от других языков; приведенный выше пример не компилируется по двум причинам: метка еще не объявлена, когда она используется, и метка должна быть непосредственно связана с оператором do, while, if или case. Кроме того, break внутри операторов if или do требует, чтобы оператор был помечен. Мы можем исправить это следующим образом, хотя изменения делают решение менее привлекательным из-за дополнительного отслеживания с помощью переменной errorFlagged, делая рефакторинг более привлекательной:

func testBreak() {
    let a = false, b = true, x = 10, y = 20, err = true
    var errorFlagged = false
    nestedIf: if !a {
        if b && x > 0 {
            if y < 100 {
                if err {
                    errorFlagged = true
                    break nestedIf
                }
                // some statements
            } else {
                // other stuff
            }
        }
    }

    // skip handling if no error flagged.
    if errorFlagged {
        print("error")
        // handle error
    }
}

Ответ 2

Например, если вы хотите описать число (со строками) со ссылкой на наборы чисел (четные/рациональные/отрицательные числа), ваш код может выглядеть примерно так:

if condition1 {
    // code
    if condition2 {
        // code
        if condition3 {
            // code
            if condition4 {
                //code
            }
        }
    }
}

Вы можете достичь той же логики, но без вложенных ifs путем рефакторинга (используя guard):

OuterIf: if condition1 {
    // code

    guard condition2 else { break OuterIf }
    // code

    guard condition3 else { break OuterIf }
    // code

    guard condition4 else { break OuterIf }
    // code
}

// reads even better when breaking out of "do"
scope: do {
    guard condition1 else { break scope }
    // code

    guard condition2 else { break scope }
    // code

    guard condition3 else { break scope }
    // code

    guard condition4 else { break scope }
    // code

}

Вы можете подумать, что это также может быть достигнуто с помощью switch и fallthrough, но это не работает с "нормальными" случаями, потому что он проверяет все условия и, если выполняется одно условие, все следующие условия даже не оцениваются.

Итак, fallthough следует условно назвать.

Это работает, но я не очень читаю, не говоря уже о его "красоте":

let x = 4
switch x {
case _ where condition1:
    // code
    if condition2 { fallthrough }
case _ where false:
    // code
    if condition3 { fallthrough }
case _ where false:
    // code
    if condition4 { fallthrough }
case _ where false:
    // code
    break
default: break
}