Как работает печать в R
У R есть привычка, которой нет ни у одного другого мейнстримного языка: в консоли инструкция печати вообще не нужна. Наберите имя переменной, нажмите Enter — и R напечатает её значение. Это автопечать, и именно поэтому учебники по R полны голых выражений.
Но у автопечати есть строгая граница: она срабатывает только для выражений на верхнем уровне. Внутри цикла for или тела функции голое значение вычисляется и молча выбрасывается:
Одинокое x печатается (оно на верхнем уровне), первый цикл не печатает ничего, а второй печатает 1, 2, 3, потому что просит об этом явно. «Мой цикл выполняется, но ничего не показывает» — один из самых частых вопросов по R, и вот весь ответ: внутри циклов и функций печать всегда ваша забота. (То же самое касается запуска скрипта через Rscript — то, что работало построчно в консоли, может замолчать внутри цикла.)
print(): формальный вариант
print() показывает значение так, как его видит R, — что делает её правильным инструментом для осмотра данных и неправильным для аккуратного вывода:
Бросаются в глаза две вещи. Строки сохраняют кавычки — print() показывает точное представление, и кавычки говорят вам, что это символьное значение. И каждая строка начинается с числа в квадратных скобках вроде [1]: это индекс первого элемента в этой строке, так что когда длинный вектор переносится на новые строки, скобка каждой строки говорит, с какого элемента она продолжается. Это подсказка для чтения векторов, а не шум.
Если нужен вывод в стиле print(), но без кавычек, подойдут и print(x, quote = FALSE), и noquote(x), — но обычно в этот момент вам на самом деле нужен cat().
cat(): вывод для людей
cat() (concatenate-and-print) пишет сырой текст: без кавычек, без префиксов-индексов, аргументы соединяются пробелами. Плата за такой контроль — ничего не добавляется за вас, включая перевод строки:
Забыть "\n" — всеобщий обряд посвящения в cat(): без него следующий кусок вывода приклеится к той же строке. Доведите завершение вызовов cat() символом "\n" до рефлекса.
Разница в кавычках между двумя функциями на самом деле — разница в том, что они показывают. print() отображает управляющие последовательности так, как вы их набрали; cat() их отрисовывает:
print() показывает \t и \n буквально внутри кавычек — полезно, когда вы отлаживаете, что именно содержит строка. cat() превращает их в настоящую табуляцию и настоящий перенос строки — полезно, когда вы формируете вывод. Выбирайте по намерению: print() — осмотреть, cat() — показать.
Форматированные отчёты: sprintf() + cat()
Разделённых пробелами аргументов cat() хватает не на всё. Для выровненного форматированного вывода — фиксированные дроби, дополненные счётчики — соберите строку через sprintf() и передайте её в cat():
%-8s дополняет каждое имя до 8 символов, а %6.2f даёт каждому баллу одинаковую ширину и два знака после запятой, поэтому столбцы выравниваются. Эта пара — рабочая лошадка базового R для сообщений о прогрессе и небольших текстовых отчётов (форматные коды разобраны в статье про строки).
message() и warning(): другой канал
cat() и print() пишут в стандартный вывод — поток, в котором лежат результаты вашей программы. message() и warning() пишут в стандартный поток ошибок, предназначенный для комментариев о ходе выполнения:
На экране оба выглядят похоже, но разделение становится важным в момент перенаправления вывода: направьте stdout скрипта в файл — и 42 попадёт в файл, а служебная заметка останется в терминале. Это и есть правило большого пальца: результаты в stdout через cat(), комментарии в stderr через message(). Поэтому же message() (а не cat()) — вежливый способ для функций и пакетов разговаривать с пользователями: вызывающий может заглушить их через suppressMessages(), не потеряв настоящий вывод.
warning() сильнее — «что-то не так, но я продолжил», — и когда скрипт выполняется под Rscript, предупреждения собираются и показываются вместе в конце, а не по ходу дела (о том, как их читать, см. статью про отладку ошибок).
Чтение пользовательского ввода: readline() и readLines()
Чтобы задать пользователю вопрос в интерактивной сессии (консоль R или RStudio), используйте readline(). Эти примеры нельзя запустить во встроенном редакторе — у него нет панели ввода, — так что попробуйте их в локальной консоли:
# Interactive sessions only:
name <- readline("What is your name? ")
cat("Hello,", name, "\n")
age <- as.numeric(readline("Your age? "))
cat("Next year you'll be", age + 1, "\n")
Две вещи, которые нужно помнить. readline() всегда возвращает строку — преобразуйте через as.numeric(), прежде чем считать, и проверьте результат на NA на случай, если пользователь ввёл не число. А в неинтерактивном скрипте readline() вообще не ждёт ввода; она мгновенно возвращает "".
Для скрипта, запускаемого через Rscript, который должен читать переданный по конвейеру или набранный ввод, читайте из стандартного ввода:
# In a script run as: echo "Ada" | Rscript greet.R
line <- readLines(con = "stdin", n = 1)
cat("Hello,", line, "\n")
readLines(con = "stdin") без n читает все строки до конца ввода — стандартная форма для скриптов-фильтров. Чтение файлов с данными — другая задача, и для неё есть инструменты получше; начните с read-csv, когда вашим входом является набор данных, а не клавиатура.
Что вы уносите с собой
- Автопечать происходит только на верхнем уровне — внутри циклов и функций вызывайте
print()илиcat()сами. print()осматривает: кавычки у строк, префиксы-индексы[1], экранирование показывается буквально.cat()представляет: сырой текст, аргументы через пробелы, а"\n"добавляете вы.sprintf()+cat()— паттерн базового R для форматированного выровненного вывода.- Результаты идут в stdout (
cat), комментарии — в stderr (message,warning). readline()— для интерактивного ввода (всегда строка!);readLines(con = "stdin")— для Rscript.
Дальше: операторы — арифметические, сравнения и логические, которые управляют каждым написанным вами условием.
Часто задаваемые вопросы
В чём разница между print() и cat() в R?
print() показывает значение так, как его представляет R: строки сохраняют кавычки, а каждая строка вывода получает префикс вида [1]. cat() пишет сырой текст без кавычек, без индексов и без автоматического переноса строки ("\n" вы добавляете сами). Используйте print() для осмотра объектов и cat() для вывода, предназначенного людям.
Почему мой цикл в R ничего не печатает?
Автопечать работает только для выражений на верхнем уровне. Внутри цикла for или тела функции голое x вычисляется и молча отбрасывается. Оберните явно: print(x) или cat(x, "\n").
Как прочитать пользовательский ввод в R?
В интерактивной сессии readline("prompt: ") читает одну введённую строку как текст (преобразуйте через as.numeric(), если нужно число). В скрипте, запущенном через Rscript, readline() не ждёт ввода — читайте из стандартного ввода через readLines(con = "stdin", n = 1).
Как напечатать без кавычек в R?
Используйте cat("hello\n") — она никогда не добавляет кавычки. Если нужна именно семантика print(), но без кавычек, подойдут print("hello", quote = FALSE) или noquote("hello").