Подтвердить что ты не робот

Есть ли способ заставить Objective-C поддерживать конструкцию переключателей с несколькими переменными?

Мне было интересно: существует ли способ сделать Objective-C поддержку конструкции с несколькими переменными switch?

Я имею в виду, что очень часто мне приходится иметь дело с проблемами, в которых решение зависит от пары переменных, а не от одной. Для длинного списка значений одной переменной можно использовать простую конструкцию switch/case:

switch (var) {
    case 0: ...
    case 1: ...
    default: ...
}

Но когда вам приходится иметь дело с комбинацией двух значений, вам часто бывает что-то вроде этого:

switch (var1) {
    case 0: 
        switch (var2) {
            case 0: ...
            case 1: ...
        }
    case 1: 
        switch (var2) {
            case 0: ...
            case 1: ...
        }        
    ...
}

И это становится все сложнее... Мне бы очень хотелось сделать что-то вроде этого:

switch (var1, var2) {
    case (0,0) : ...
    case (1,0) : ...
    case (*,1) : ...
    default: ...
}

что приведет к созданию более простой и понятной конструкции. Существует ли какое-либо решение для поддержки такой структуры? Или небольшое изменение этого?

4b9b3361

Ответ 1

Мне нравится ответ от saphrosit, но я постараюсь сделать его понятным.

Представьте возможные результаты вашей проблемы как квадраты в сетке, где один край края сетки представляет значения var1, а другой край представляет возможные значения var2, а затем, если вы увеличите счетчику по квадратам в сетке вы бы получили что-то вроде этого

      ||                              var1                                   |    
      ||    0    |     1     |     2     | ... |     j     | ... |   n-1     |
======++=====================================================================|
    0 ||    0    |     1     |     2     | ... |     j     | ... |   n-1     |
   ---||---------+-----------+-----------+-----+-----------+-----+-----------|
    1 ||    n    |    n+1    |    n+2    | ... |    n+j    | ... |  n+(n-1)  |
   ---||---------+-----------+-----------+-----+-----------+-----+-----------| 
    2 ||   2*n   |   2*n+1   |  2*n+2    | ... |   2*n+j   | ... | 2*n+(n-1) |
 v ---||---------+-----------+-----------+-----+-----------+-----+-----------|
 a    ||    .    |     .     |     .     |     |     .     |     |  .        |
 r ---||---------+-----------+-----------+-----+-----------+-----+-----------|
 2  i ||   i*n   |   i*n+1   |   i*n+2   | ... |   i*n+j   | ... | i*n+(n-1) |
   ---||---------+-----------+-----------+-----+-----------+-----+-----------|
      ||    .    |      .    |      .    |     |     .     |     |  .        |
  ----||---------+-----------+-----------+-----+-----------+-----+-----------|
  m-1 || (m-1)*n | (m-1)*n+1 | (m-1)*n+2 | ... | (m-1)*n+j | ... |   mn-1    | <-- (m-1)*n+(n-1) = m*n-n + (n-1) = mn-1
------||---------+-----------+-----------+-----+-----------+-----+-----------|

Это называется основной матрицей строк, так как вы начинаете с подсчета по строкам. Существует также основная матрица столбцов, в которой вы начинаете считать первый, а не наоборот. Вот как матрицы хранятся в библиотеке C BLAS, поэтому они должны быть очень похожими на многих людей.

В вашем случае результат, который вы ищете, может быть адресован как var3 = var2*n + var1, вы можете проложить это в коде как

#define N 10 // Maximum size of var1

int main() {

   int var1 = 1;
   int var2 = 1;

   switch(var1 + var2 * N){
      case 1 + 1 * N: printf("One One"); break;
      case 2 + 2 * N: printf("Two Two"); break;
      default:
      printf("Bada Bing");
   }

   return 0;
}

ПРИМЕЧАНИЕ: код, который был здесь ранее, не работал бы, это работает.

Ответ 2

В вашем вопросе вы упомянули: "То, что я действительно хотел бы сделать, это что-то вроде этого:"

switch (var1, var2) {
    case (0,0) : ...
    case (1,0) : ...
    case (*,1) : ...
    default: ...
}

Если это так, ваши возможные значения находятся в диапазоне {0..n}, вы можете использовать два метода.

  • Вы можете создать многомерный массив селекторов и затем выберите правильный селектор используя var1, var2. (Этот метод более эффективен благодаря построению селекторов во время компиляции)

  • Вы можете создать селектор   имя, основанное на значениях   var, var2.

В этом фрагменте кода приведены примеры BOTH.

- (void) case00 {
    NSLog(@"Case ZeroZero");
}

- (void) testSelectorIdea {
     NSInteger var1 = 0;
     NSInteger var2 = 0;

// ----- ARRAY OF SELECTORS METHOD ----
    SEL selectors[2][2] = {@selector(case00),@selector(case01), @selector(case10), @selector(case11)};
    [self performSelector:selectors[var1][var2]];


// ----- SELECTOR CONSTRUCTION METHOD ----
    NSString * selectorName = [NSString stringWithFormat:@"case%d%d",var1,var2];
    SEL  selector = NSSelectorFromString(selectorName);
    [self  performSelector:selector];

}

Ответ 3

Как говорили другие, если вы захотите это сделать, вам следует подумать о том, как лучше структурировать ваши данные. Вам кажется, что вы имеете дело со скалярными типами. Я, как правило, немного разбираюсь в С++, и вы можете интегрировать его в проект objective-c, используя objective-c ++. Тем не менее, если вы уверены, что хотите, что вы говорите, и хотите, чтобы вы не противились злу препроцессору, вы можете попробовать что-то вроде этого:

#define BEGIN_SWITCH(type,...) ({  typedef type T; T switchVars[] = { __VA_ARGS__ }; BOOL performAction;

#define CASE(...) { \
            T caseVars[] = { __VA_ARGS__ }; \
            performAction = YES; \
            size_t count = MIN(sizeof(switchVars), sizeof(caseVars)) / sizeof(T); \
            for (size_t i = 0 ; i < count / sizeof(T) ; i++) \
            { \
                if (caseVars[i] != switchVars[i]) \
                { \
                    performAction = NO; \
                    break; \
                } \
            } \
        } \
        if (performAction)

#define END_SWITCH });

int main (int argc, char const *argv[])
{
    id pool = [[NSAutoreleasePool alloc] init];

    int a1 = 0;
    int a2 = 5;
    int a3 = 10;

    BEGIN_SWITCH(int, a1, a2, a3)
        CASE(0,5) NSLog(@"0,5");
        CASE(1,2,3) NSLog(@"1,2,3");
        CASE(0,5,10) NSLog(@"0,5,10");
        CASE(1) NSLog(@"1");
    END_SWITCH

    [pool drain];

    return 0;
}

Это не совсем так, как switch/case, поскольку вы не можете складывать несколько case: clauses поверх oneanother. Вам придется добавить по умолчанию и как-то сломаться - возможно, вы могли бы сделать это с помощью некоторых дополнительных макросов и перейти к перерыву. Стандартные оговорки в отношении prereocessor применяются: это не так, как Objective-C, и будет подвержен сильным синтаксическим ошибкам. Но если вы действительно хотите изменить синтаксис языка, то ваши варианты либо что-то вроде этого, либо получить работу с Apple.

Ответ 4

Не решение, просто обходное решение: вы можете подумать над чем-то вроде этого

SInt32 var1, var2;
/*...*/
SInt64 var3 = var1<<32 + var2;

switch(var3) {
 .
 .
 .
}

если ваши вары имеют какое-то определенное свойство, которое вы можете использовать, чтобы сделать некоторые небольшие упрощения, то есть, если vars являются < 10, то вы можете использовать

 var3 = 10*var1+var2;

Ответ 5

Вы уверены, что это хороший стиль программирования, чтобы иметь такие конструкции:)? Оператор switch предназначен для ускорения нескольких операторов if() else if(), но когда вам нужно будет сравнить несколько переменных, оптимизация которых будет идти.

Один способ - использовать логические сдвиги/другие операции для размещения нескольких переменных в одном, а другой - if ((a == 0) и (b == 0)) {...} else if ((a == 0) && (b == 1)).... Это не займет много места.

Ответ 6

Из-за существования ObjC-Runtime должно быть возможно создать замену коммутатора такими вещами, как селекторный тип SEL/@selector ( )/performSelector, NSSelectorFromString, NSArrays/NSdictionaries и NSIndexPathes, то есть более мощный, чем оператор c-switch.
Но он не будет проживать на языковом уровне, так как этот код Python не соответствует.

Ответ 7

Как насчет чего-то типа:

switch ([NSString StringWithFormat: @"%d,%d", var1, var2]) {
    case (@"0,0") : ...
    case (@"1,0") : ...
    case (@"*,1") : ...
    default: ...
}

Проблема заключалась бы в *, 1, но вы могли бы либо записать все, либо сделать contains @",1" (я забыл правильный синтаксис atm)