Понимание синтаксиса сложных блоков

Я начинаю разработку Objective C и iOS, но 13-летний ветеран .NET. Мне трудно мысленно диаграммировать следующее объявление, которое появилось в Программирование с помощью Objective C:

void (^(^a)(void (^) (void))) (void) = ...

Он используется в качестве примера того, почему нужно использовать typedef для определения блоков, но я хочу понять, что я ищу, чтобы лучше понять синтаксис определения блока в первую очередь.

Вот как я его нарисовал до сих пор:

enter image description here

Где я сталкиваюсь с проблемами, так это то, как я понимаю базовый синтаксис:

[return_val] (^[block_name]) ([block_args]) = ...

Если это так, то у меня есть блок, который возвращает void и не имеет аргументов, но называется (^a) (void (^) void). Значение имени моего блока, а не прямой строки, само является блоком.

Ясно, что я что-то пропустил. Может кто-то пролить свет на него? Согласно сайту, это упрощает:

typedef void (^SimpleBlock) (void);
SimpleBlock (^complexBlock) (SimpleBlock) = ...

Мне просто не хватает как.

Изменить: Третья пустота должна была быть в круглых скобках. Я это исправил. Это неправильно в изображении, но мне не хотелось переделывать весь образ только для этого.:) Если он окажется источником моей проблемы, я исправлю его здесь.

Ответ 1

В вашем примере вам не хватает скобок для третьего void

void (^(^a)(void (^)(void)))(void)

Теперь сломайте его. Основной синтаксис для возврата блока из функции:

void (^f())(void) { 
    return ^{}; 
}

В этом примере возвращаемый блок не принимает аргументов и возвращает void.

Теперь давайте построим ваш пример.

void     (^myBlock)(void);                       // Block returning void, taking no args
void     (^myBlock)(void (^)(void));             // Block returning void, taking block as arg
int      (^myBlock)(void (^)(void));             // Block returning int, taking block as arg
void (^  (^myBlock)(void (^)(void))  )(void);    // Block returning block, taking block as arg

Я выровнял центральную часть в каждой строке, чтобы упростить ее чтение. Таким образом, сложная часть, кажется, возвращает блок. В последней строке мы использовали ранее описанный выше синтаксис, чтобы вернуть блок из функции.

Очевидно, что typedefs упрощает чтение.

EDIT:
Рассмотрим этот пример, где в первой строке я заменяю int на block на интуитивный синтаксис возврата:

void (^ )(void) (^myBlock)(void (^)(void));          // Syntax we 'intuitively would use'
void (^         (^myBlock)(void (^)(void))  )(void); // Official syntax

Я не уверен на 100% того, что я собираюсь сказать, но мое подозрение в том, что причина этого странного синтаксиса заключается в том, что синтаксический анализатор в компиляторе не запутался. Первый "интуитивный" синтаксис заставил компилятор думать, что у нас есть блок, не содержащий аргументов, возвращающих void, а остальные символы будут считаться синтаксической ошибкой.

По-моему, синтаксис - это то, о чем вы не слишком много задаете (вы можете его критиковать, конечно), потому что это часть дизайна на языке, и мы должны следовать правилам (заданы некоторые, надеюсь, умные инженеры ) для компиляции нашего кода.

Ответ 2

void (^(^a)(void (^) (void))) (void)

Разбить этот синтаксис на несколько частей:

  • a - переменная.
  • он может быть разыменован как c указатель "*" синтаксисом "^": ^a.
  • (^a)(void (^) (void) - это блок с именем a и принимает параметр (void (^) (void).
  • это возвращаемое значение может быть разыменовано, чтобы получить информацию о блоке: ^(^a)(void (^) (void)). (и, следовательно, возвращаемое значение является указателем блока)
  • этот возвращенный блок не принимает параметр: (^(^a)(void (^) (void))) (void).
  • и этот возвращенный блок не нуждается в возвращаемом значении: void (^(^a)(void (^) (void))) (void)

Итак, пусть (^a) (void (^) void) не Meaning the name of my block, rather than being a straight string, is itself a block.. Блок-литерал не должен быть

 [return_val] (^[block_name]) ([block_args])

complier примет код после каретки как блока.