Есть ли язык программирования с лучшим подходом к операторам с отключенным отключением?
Это тот же синтаксис, что и слишком много языков:
switch (someValue) {
case OPTION_ONE:
case OPTION_LIKE_ONE:
case OPTION_ONE_SIMILAR:
doSomeStuff1();
break; // EXIT the switch
case OPTION_TWO_WITH_PRE_ACTION:
doPreActionStuff2();
// the default is to CONTINUE to next case
case OPTION_TWO:
doSomeStuff2();
break; // EXIT the switch
case OPTION_THREE:
doSomeStuff3();
break; // EXIT the switch
}
Теперь все, что вам известно, что инструкции break
требуются, потому что switch
будет продолжаться до следующего case
, когда отсутствует инструкция break
. Мы имеем пример с OPTION_LIKE_ONE
, OPTION_ONE_SIMILAR
и OPTION_TWO_WITH_PRE_ACTION
. Проблема в том, что нам нужно только "переходить к следующему случаю" очень редко. И очень часто мы помещаем разрыв в конце case
.
Очень легко начинающему забыть об этом. И один из моих учителей C даже объяснил это нам, как если бы это была ошибка на языке C (не хотите говорить об этом:)
Я хотел бы спросить, есть ли какие-либо другие языки, о которых я не знаю (или забыл), которые обрабатывают switch/case следующим образом:
switch (someValue) {
case OPTION_ONE: continue; // CONTINUE to next case
case OPTION_LIKE_ONE: continue; // CONTINUE to next case
case OPTION_ONE_SIMILAR:
doSomeStuff1();
// the default is to EXIT the switch
case OPTION_TWO_WITH_PRE_ACTION:
doPreActionStuff2();
continue; // CONTINUE to next case
case OPTION_TWO:
doSomeStuff2();
// the default is to EXIT the switch
case OPTION_THREE:
doSomeStuff3();
// the default is to EXIT the switch
}
Второй вопрос: есть ли какой-либо исторический смысл, почему это так в C? Может быть продолжение следующего случая было использовано гораздо чаще, чем мы используем его в наши дни?
Ответы
Ответ 1
Из этой статьи я могу перечислять некоторые языки, для которых не требуется инструкция break
-like:
- Ada (нет провала)
- Эйфель (без провала)
- Паскаль (без провала)
- Go -
fallthrough
- Perl -
continue
- Ruby (нет провала)
- VB, VBA, VBS, VB.NET(без провала)
- Продолжение следует кем-то еще...
Ваш второй вопрос довольно интересный. Предполагая, что только C, Я верю, это решение связывает язык. Поскольку break
является скачком, он должен быть явно записан.
Ответ 2
Scala сопоставление шаблонов Я думаю, это большое улучшение в этих случаях.:)
object MatchTest2 extends Application {
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
}
println(matchTest("two"))
}
Пример из scala -lang.org
Ответ 3
И VB.NET справляется с этим немного больше, как вы ожидаете, что он будет работать.
Select Case i
Case 1 to 3
DoStuff(i)
Case 4,5,6
DoStuffDifferently(i)
Case Is >= 7
DoStuffDifferentlyRedux(i)
Case Else
DoStuffNegativeNumberOrZero(i)
End Select
Нет никакого падения вообще, без возможности использования Goto
Ответ 4
Вот ответ:
http://en.wikipedia.org/wiki/Switch_statement
Он вызвал оператор fall-through (continue
в примере) и существует на следующих языках:
Go, Perl, С#
В С# он не будет компилироваться без инструкции break
или goto case
(кроме случаев, когда нет предварительного действия).
Ответ 5
PASCAL не имеет провалов
Ответ 6
Я думаю, что ответ на ваш вопрос о том, почему именно этот метод сосредотачивается на двух типах поведения, оба имеют отношение к сгенерированному ассемблеру кода из источника C.
Первое заключается в том, что в сборке выполняется текущая команда, и если нет команды перехода или какой-либо другой команды управления потоком, команда на следующем адресе будет выполнена. Выполнение наивного компиляции оператора switch для сборки приведет к генерации кода, который только начнет выполнение первой команды, которая должна была бы увидеть, было ли условие соответствия...
Вторая причина связана с понятием таблица ветвей или список переходов. В основном, компилятор может понять, что он знает о вашей ценности, и создать очень эффективный машинный код для одного и того же. Возьмем, например, простую функцию типа atoi, которая преобразует строковое представление числа и возвращает его в целочисленной форме. Упрощая все, чтобы поддерживать только одну цифру, вы можете написать код, похожий на этот:
int atoi(char c) {
switch (c) {
case '0': return 0;
case '1': return 1;
// ....
}
}
Наивный компилятор, возможно, просто преобразует это в ряд блоков if/then, что означает, что для числа 9 будет принято значительное количество циклов процессора, а 0 - почти сразу. Используя таблицу ветвей, компилятор может испустить некоторую сборку [psuedo], которая сразу же "прыгнет" в правильное предложение return:
0x1000 # stick value of c in a register
0x1004 # jump to address c + calculated offset
# example '0' would be 0x30, the offset in for this sample
# would always be 0x0FD8... thus 0x30 + 0x0FD8 = 0x1008
0x1008 # return 0
Апология: мои навыки сборки и C довольно ржавые. Надеюсь, это поможет прояснить ситуацию. 0x
Ответ 7
Эй, не забывайте КОБЕЛЬ ОЦЕНКИ:
EVALUATE MENU-INPUT
WHEN "0" PERFORM INIT-PROC
WHEN "1" THRU "9" PERFORM PROCESS-PROC
WHEN "R" PERFORM READ-PARMS
WHEN "X" PERFORM CLEANUP-PROC
WHEN OTHER PERFORM ERROR-PROC
END-EVALUATE.
Ответ 8
Ada не имеет провалов и требует, чтобы все значения были явно обработаны, или добавлено предложение "others" для обработки остальных.
Оператор SQL CASE также не проходит.
XSLT имеет то, что не проходит.
Кажется, что C и производные языки имеют провал. Это довольно коварно, и единственное реальное использование, которое я видел, это реализовать устройство duff.
http://www.adaic.org/whyada/intro4.html
Ответ 9
У Python его нет.
Достаточно привыкнуть, но у меня есть некоторые ужасные воспоминания, которые охотятся через массивные блоки switch
назад в мои дни С#. Я намного счастливее без него.
Ответ 10
Хотя не то, что вы просили, Groovy имеет очень мощный оператор switch
Ответ 11
OP говорит о "проваливании", но очень редко я когда-либо был в этом уверен.
Много раз, однако, я был немного по дизайну, который не расширяется. К примеру, "switch (kbHit)" с несколькими сотнями ключей, которые являются кошмаром для обслуживания, и частым местом для "божественных методов" и гигантскими грудами спагетти-кода.
Использование переключателя часто является признаком плохого объектно-ориентированного программирования. Как ответил другой человек: "2 использования Switch в 48 исходных файлах", в одном из его приложений, показывает программиста, который не сильно полагается на эту конструкцию. Из его метрики я предполагаю, что он, вероятно, по крайней мере хороший структурированный программист, и, вероятно, также понимает OOP/OOD.
Программисты OOP (не обязательно только С++), и даже чистые пользователи C, у которых нет метода описания объектов, навязанных им, могут реализовать контейнер "инверсии контроля", который публикует "ключ был поражен", и позволяет подписчикам подключите их обработчики для "на клавиатуре x". Это может значительно упростить чтение кода.
Ответ 12
Чистая спекуляция, но:
Я иногда пишу C или Java, в которых говорю что-то вроде:
switch (tranCode)
{
case 'A':
case 'D':
case 'R':
processCredit();
break;
case 'B':
case 'G':
processDebit();
break;
default:
processSpecial();
}
То есть я намеренно использую fall-thru, чтобы несколько значений запускали одну и ту же операцию.
Интересно, думают ли изобретатели C, когда они создали инструкцию SWITCH, что это будет нормальное использование.
Ответ 13
Tcl не проходит автоматически.
Ответ 14
В объектно-ориентированных языках вы используете шаблон Chain of Responsibility. Как это реализовано, может отличаться. То, что вы описываете в своем примере, смешивает машину состояний с поведением, злоупотребляя оператором switch. Для вашего конкретного примера шаблон цепочки ответственности с параметром, который цепь оценивает как шаблон State, который мутирует, когда он идет вниз цепочки, будет подходящей реализацией.
Ответ 15
Языки слишком много, и я не могу точно ответить, что там нет такого языка, если он является "производным" от синтаксиса C, потому что другие языки, использующие разные синтаксисы, и где случай не "продолжается" естественным образом существуют, например Fortran. Я не знаю языки, которые используют явное "продолжение", чтобы продолжить следующий случай.
Я считаю, что это историческая причина из-за того, что такой случай можно запрограммировать на "низком уровне". Более того, синтаксический аспект дела - это ярлык ярлыка, а break работает как в циклах, поэтому вы можете представить себе такой эквивалент:
if ( case == 1 ) goto lab1;
if ( case == 2 ) goto lab2;
if ( case == 3 ) goto lab3;
//...
default:
// default
goto switch_end;
lab1:
// do things
goto switch_end; // if break is present
lab2:
// do things, and follow to lab3
lab3:
// lab3 stuffs
goto switch_end;
//
...
switch_end: // past all labS.
Ответ 16
Другие языки без слайдов:
XSLT
JSTL
Алголь
PL/1
Ответ 17
Лима делает это так:
if someValue == ?1 ::
OPTION_ONE: fall
OPTION_LIKE_ONE: fall
OPTION_ONE_SIMILAR:
doSomeStuff1[]
;; the default is to EXIT the switch
OPTION_TWO_WITH_PRE_ACTION:
doPreActionStuff2[]
fall ;; fall through to the next case
OPTION_TWO:
doSomeStuff2[]
OPTION_THREE:
doSomeStuff3[]