Каковы различия между операторами присваивания =
и <-
в R?
Как ваш пример показывает, =
и <-
имеют несколько иной приоритет оператора (который определяет порядок вычисления , когда они смешиваются в одном выражении). На самом деле, ?Syntax
в R выдает следующую таблицу приоритетов операторов, от высшего к низшему:
…
‘-> ->>’ rightwards assignment
‘<- <<-’ assignment (right to left)
‘=’ assignment (right to left)
…
Но единственная ли это разница?
Поскольку вы спрашивали об операторах присваивания : да, это единственная разница. Тем не менее, вы были бы прощены за то, что поверили в обратное. Даже документация R ?assignOps
утверждает, что есть больше различий:
Оператор <-
может использоваться где угодно, тогда как оператор =
допускается только на верхнем уровне (например, в полном выражении, набранном в командной строке) или в качестве одного из подвыражений в ограниченном списке выражений.
Давайте не будем заострять внимание на этом: документация на R (слегка) неверна [ 1 ] . Это легко показать: нам просто нужно найти контрпример для =
оператора, который не (а) не находится на верхнем уровне и не (b) является подвыражением в ограниченном списке выражений (то есть {…; …}
). - Без дальнейших церемоний:
x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
Ясно, что мы выполнили присваивание =
вне контекста (a) и (b). Итак, почему документация о ядре языка R была неправильной в течение десятилетий?
Это потому, что в синтаксисе R символ =
имеет два разных значения, которые обычно смешиваются:
- Первое значение как оператор присваивания . Это все, о чем мы говорили до сих пор.
- Второе значение - не оператор, а синтаксический маркер, который сигнализирует именованный аргумент, передаваемый в вызове функции. В отличие от
=
оператора, он не выполняет никаких действий во время выполнения, он просто изменяет способ анализа выражения.
Посмотрим.
В любой части кода общего вида ...
‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)
... =
это токен, который определяет передачу именованного аргумента: это не оператор присваивания. Кроме того, =
полностью запрещено в некоторых синтаксических контекстах:
if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …
Любое из них вызовет ошибку «неожиданно» = «в‹ bla ›».
В любом другом контексте =
относится к вызову оператора присваивания. В частности, простое размещение скобок вокруг подвыражения делает любое из вышеперечисленного (а) действительным и (б) назначением . Например, следующее выполняет назначение:
median((x = 1 : 10))
Но и:
if (! (nf = length(from))) return()
Теперь вы можете возразить, что такой код ужасен (и вы можете быть правы). Но я взял этот код из base::file.copy
функции (заменив <-
на =
) - это распространенный шаблон в большей части основной кодовой базы R.
Оригинальное объяснение Джона Chambers , которым документация по R, вероятно , на основе, на самом деле объясняет это правильно:
[ =
присваивание] разрешено только в двух местах грамматики: на верхнем уровне (как полная программа или пользовательское выражение); и когда он изолирован от окружающей логической структуры, скобками или дополнительной парой скобок.
Признание: я солгал раньше. Там является одна дополнительная разница между =
и <-
операторами: они называют различные функции. По умолчанию эти функции делают то же самое, но вы можете переопределить любую из них отдельно, чтобы изменить поведение. В отличие от этого, <-
и ->
(назначение слева направо), хотя синтаксически различны, всегда вызывают одну и ту же функцию. Переопределение одного переопределяет другое. Знание этого редко бывает практичным, но его можно использовать для забавных махинаций .
<-
символа приходят от старых APL клавиатур , которые фактически имели один<-
ключ на них.