Понимание синтаксиса сложных блоков
Я начинаю разработку 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 примет код после каретки как блока.