Весь код R перед выполнением анализируется в дереве (см. Выражения из Advanced R для получения дополнительной информации).Чтобы иметь несколько выражений в любой точке дерева, R должен создать оболочку / контейнер для хранения этих выражений.И это в основном то, что представляет класс {
.Он определяет блок кода.Это коллекция выражений для оценки.Подумайте, если это как функция, где каждое выражение, которое вы хотите оценить, является параметром (по крайней мере, так оно и хранится в дереве).А блоки кода просто возвращают значение, возвращаемое последним выражением.Сравните
as.list(quote({a; b}))
# [[1]]
# `{`
# [[2]]
# a
# [[3]]
# b
as.list(quote(c(a, b)))
# [[1]]
# c
# [[2]]
# a
# [[3]]
# b
Видите, как они превращаются в подобные структуры в R?За «именем функции» сначала следует список параметров.Вы даже можете вызвать {
как обычную функцию
`{`(a<-1, 5, a+2)
# [1] 3
(обратите внимание, что последнее значение является единственным возвращаемым значением).Также обратите внимание, что блоки кода не создают свою собственную область видимости, поэтому переменная a
будет определена в глобальной среде, если вы запустите ее на консоли.
Вы можете создать объект этого типа, просто заключив в кавычкикодовый блок
class(xx <- quote({a; b}))
# [1] "{"
xx
# {
# a
# b
# }
или путем создания вызова с символами в кавычках
class(xx <- as.call(list(quote(`{`), quote(a), quote(b))))
# [1] "{"
xx
# {
# a
# b
# }
И это не всегда тот случай, когда тело функции будет иметь класс {
.Например,
x <- function(a) a+1
y <- function(a) {b <- sqrt(a); b+2}
class(body(x))
# [1] "call"
class(body(y))
# [1] "{"
, потому что мы хотели запустить более одного оператора в функции y
, нам нужно было поместить эти выражения в блок кода.Поскольку x
вызывает только одно выражение, нам не нужно было использовать {
, поэтому у него другой класс.