Выражения и автопечать
R — язык выражений: почти каждая написанная вами строка порождает значение. В консоли выражение, набранное само по себе, вычисляется, и его значение печатается автоматически — print() не нужен:
Каждый результат предваряется префиксом [1] — так R сообщает позицию первого показанного значения; первый намёк на то, что R мыслит векторами (об этом ниже). У автопечати есть особенность, о которой стоит знать с первого дня: она работает для голых выражений на верхнем уровне. То же самое выражение внутри тела функции или цикла for не напечатает ничего — поэтому в скриптах для вывода, который вы обязаны увидеть, используют явные cat() или print().
Присваивание: стрелка
Оператор присваивания в R — <-, стрелка, указывающая на имя, которое получает значение:
Читайте radius <- 5 как «radius получает 5». Да, = тоже работает для присваивания на верхнем уровне, и да, новички спрашивают, зачем набирать два символа вместо одного. Ответ — соглашение, у которого есть зубы: все серьёзные руководства по стилю, документация базового R и практически весь код на R, который вам когда-либо встретится, используют <- для присваивания, оставляя = для одной конкретной задачи — именования аргументов внутри вызовов функций (следующий раздел). Соблюдение этого соглашения делает две операции визуально различимыми. В RStudio Alt+- (Option+- на macOS) набирает стрелку за вас.
Обратите внимание: присваивание не печатается автоматически — area <- 78.5 сохраняет значение молча. Поэтому в сниппете выше и нужен print().
Чувствительность к регистру
R строго чувствителен к регистру — и в именах, которые создаёте вы, и в именах, которые даёт сам язык:
Это две разные переменные. Точно так же mean() — функция, а Mean() не существует. Когда R встречает вас сообщением object 'x' not found или could not find function, проверьте регистр раньше всего остального — это самая частая ошибка начинающих.
Вызовы функций и именованные аргументы
Функции вызываются со скобками, аргументы разделяются запятыми. Аргументы могут сопоставляться по позиции, по имени или смешанно:
Вызов seq() показывает синтаксис именованных аргументов R — и именно здесь = отрабатывает своё место: внутри вызова name = value помечает аргумент. Именованные аргументы избавляют от необходимости помнить порядок параметров и делают вызовы самодокументируемыми; seq(0, 100, 25) работает точно так же, но говорит читателю меньше. Рабочее соглашение: первый аргумент (обычно данные) передавайте по позиции, остальные именуйте.
Справка по любой функции — в одно нажатие: ?seq в консоли открывает её документацию.
Всё есть вектор
Идея, из-за которой R ощущается иначе, чем другие языки: голых одиночных чисел не бывает. Даже 5 — это вектор длины один, а операции применяются поэлементно к целым векторам:
Никакого цикла — а преобразован каждый элемент. В большинстве языков это три итерации цикла for; в R это арифметика. Это векторизация, и она определяет всё — операторы сравнения, строковые функции и математические функции работают так же. Именно поэтому в идиоматичном R гораздо меньше циклов, чем можно было бы ожидать; полная история — в статье про векторы.
Фигурные скобки и блоки
Многострочные тела — для if, циклов и функций — группируются фигурными скобками {}:
Обратите внимание на две вещи. Условие живёт в круглых скобках, и это просто if, а не if: или if ... then. И, в отличие от Python, отступы в R не несут смысла — блок задают скобки, а отступы нужны людям. Опускать скобки в однострочниках законно, но это классический источник ошибок при правках; просто всегда их ставьте.
Пробелы и точки с запятой
R игнорирует лишние пробелы, а перевод строки завершает инструкцию — точка с запятой не требуется:
Перенос на другую строку работает потому, что третья строка заканчивается на +, и R понимает, что выражение не завершено. Это единственное правило, которое нужно помнить при разбиении длинных строк: переносите после оператора или запятой, никогда перед ними, иначе R сочтёт первую строку законченной. Точки с запятой существуют лишь для того, чтобы впихнуть две инструкции в одну строку (a <- 1; b <- 2) — законно, не одобряется, легко избегается.
Стиль: как пишут код на R
Помимо грамматики, у R есть сильные соглашения сообщества (закреплённые в руководстве по стилю tidyverse, которому следует большая часть экосистемы):
<-для присваивания,=только для аргументов внутри вызовов.- Имена в
snake_case:monthly_revenue, а неmonthlyRevenueилиmonthly.revenue. Точки в именах R законны, но их лучше избегать — они пересекаются с шаблоном именования, который использует внутренняя кухня R. - Пробелы вокруг операторов (
x <- a * 2, а неx<-a*2) и после запятых. - Отступ в четыре пробела внутри скобок (некоторые команды используют два; выберите одно и придерживайтесь).
- Одна инструкция на строку.
Ничего из этого не требует интерпретатор. Всё это потребует любой, кто читает ваш код. Продолжение темы именования — в статье про переменные.
Что вы уносите с собой
- R вычисляет выражения и автоматически печатает голые выражения в консоли — но не внутри функций или циклов.
- Присваивайте через
<-(«получает»);=используйте только для именования аргументов в вызовах функций. - R полностью чувствителен к регистру — опечатки в регистре вызывают большинство ранних ошибок «not found».
- Всё есть вектор, и операции применяются поэлементно:
c(1, 2, 3) * 2— это2 4 6, без цикла. - Фигурные скобки задают блоки, переводы строк завершают инструкции, а
snake_caseи соглашения о пробелах делают ваш код похожим на код всех остальных.
Дальше: комментарии — как аннотировать код на R и что делать с отсутствующим в R синтаксисом блочных комментариев.
Часто задаваемые вопросы
Что означает <- в R?
<- — это оператор присваивания в R: x <- 5 сохраняет значение 5 под именем x. Читайте его как «получает». = тоже присваивает на верхнем уровне, но принятое в сообществе соглашение — его требует любое серьёзное руководство по стилю — это <- для присваивания и = только для именования аргументов внутри вызовов функций.
Чувствителен ли R к регистру?
Да, полностью. total, Total и TOTAL — три разных имени, а вызов Mean(x) вместо mean(x) — это ошибка, а не предупреждение. Сообщения «could not find function» или «object not found» очень часто оказываются просто опечаткой в регистре.
Нужны ли в R точки с запятой?
Нет. Инструкцию завершает перевод строки. Точка с запятой нужна только чтобы втиснуть две инструкции в одну строку (a <- 1; b <- 2), что руководства по стилю всё равно не одобряют. Пишите по одной инструкции на строку — и забудьте про точки с запятой.
Что значит, что R векторизован?
Базовые операции R работают сразу над целыми векторами. c(1, 2, 3) * 2 даёт 2 4 6 — умножение применяется к каждому элементу без всякого цикла. Большая часть кода, который в другом языке был бы циклом for, в R умещается в одно выражение.