OR в коммутационном корпусе?

Возьмем простой случай переключения, который выглядит так:

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.someValue :
        case R.id.someOtherValue:
            // do stuff
            break;
    }
}

Интересно, почему не разрешается использовать оператор ||? Как

switch (v.getId()) {
    case R.id.someValue || R.id.someOtherValue:
        // do stuff
        break;
}

Конструкция switch-case очень похожа на инструкцию if-else, однако вы можете использовать оператор OR в if. Каковы предпосылки для switch-case, чтобы не принимать этот оператор?

Ответы

Ответ 1

Каковы фоны для случая коммутатора, чтобы не принимать этот оператор?

Потому что case требует постоянного выражения в качестве значения. А поскольку выражение || не является константой времени компиляции, это недопустимо.

От JLS Раздел 14.11:

Знак коммутатора должен иметь следующий синтаксис:

SwitchLabel:
    case ConstantExpression:
     case EnumConstantName:
     default:


Под капотом:

Причина, позволяющая просто постоянное выражение в случаях, может быть понята из JVM Spec Section 3.10 - Компиляция переключателей:

Компиляция операторов switch использует инструкции tableswitch и lookupswitch. Команда tableswitch используется, когда случаи коммутатора могут быть эффективно представлены в виде индексов в таблицу целевых смещений. Цель по умолчанию для коммутатора используется, если значение выражения коммутатора выходит за пределы допустимых индексов.

Итак, для ярлыка case, который будет использоваться tableswitch в качестве индекса в таблице смещений цели, значение случая должно быть известно во время компиляции. Это возможно только в том случае, если значение case является постоянным выражением. И выражение || будет оцениваться во время выполнения, и значение будет доступно только в это время.

В том же разделе JVM: switch-case:

switch (i) {
    case 0:  return  0;
    case 1:  return  1;
    case 2:  return  2;
    default: return -1;
}

скомпилирован для:

0   iload_1             // Push local variable 1 (argument i)
1   tableswitch 0 to 2: // Valid indices are 0 through 2  (NOTICE This instruction?)
      0: 28             // If i is 0, continue at 28
      1: 30             // If i is 1, continue at 30
      2: 32             // If i is 2, continue at 32
      default:34        // Otherwise, continue at 34
28  iconst_0            // i was 0; push int constant 0...
29  ireturn             // ...and return it
30  iconst_1            // i was 1; push int constant 1...
31  ireturn             // ...and return it
32  iconst_2            // i was 2; push int constant 2...
33  ireturn             // ...and return it
34  iconst_m1           // otherwise push int constant -1...
35  ireturn             // ...and return it

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

Ответ 2

чувак вроде этого

    case R.id.someValue :
    case R.id.someOtherValue :
       //do stuff

Это то же самое, что и оператор OR между двумя значениями Из-за этого случая оператора нет в корпусе коммутатора

Ответ 3

Коммутатор не такой, как if-else-if.

Коммутатор используется, когда есть одно выражение, которое оценивается по значению, и это значение может быть одним из предопределенных значений. Если вам нужно выполнить несколько операций с булевыми/сравнительными операциями, тогда if-else-if необходимо использовать.

Ответ 4

foreach (array('one', 'two', 'three') as $v) {
    switch ($v) {
        case (function ($v) {
            if ($v == 'two') return $v;
            return 'one';
        })($v):
            echo "$v min \n";
            break;


    }
}

это отлично подходит для языков, поддерживающих корпуса