Spec-Zone.ru › Elixir 1.18

Исходный код IO

Функции для обработки ввода-вывода (IO).

Многие функции в этом модуле ожидают в качестве аргумента устройство ввода-вывода. Устройство ввода-вывода должно быть PID или атомом, представляющим процесс. Для удобства Elixir предоставляет :stdio и :stderr в качестве сокращений для Erlang's :standard_io и :standard_error.

Большинство функций ожидают chardata. В случае передачи другого типа функции преобразуют эти типы в строку через протокол String.Chars (как показано в типах). Более подробную информацию о chardata см. в разделе "Данные IO" ниже.

Функции этого модуля используют именование в стиле UNIX, где это возможно.

Устройства ввода-вывода

Устройство ввода-вывода может быть атомом или PID. В случае атома, атом должен быть именем зарегистрированного процесса. Кроме того, Elixir предоставляет два сокращения:

  • :stdio - сокращение для :standard_io, которое отображает текущий Process.group_leader/0 в Erlang

  • :stderr - сокращение для именованного процесса :standard_error, предоставляемого в Erlang

Устройства ввода-вывода сохраняют свое положение, что означает, что последующие вызовы функций чтения или записи будут начинаться с места, где устройство было в последний раз обработано. Положение файлов можно изменить с помощью функции :file.position/2.

Данные IO

Данные IO — это тип данных, который может использоваться в качестве более эффективной альтернативы двоичным данным в определенных ситуациях.

Значение типа Данные IO — это двоичная строка или список, содержащий байты (целые числа в диапазоне 0..255), или вложенные данные IO. Тип рекурсивный. Рассмотрим пример одного из возможных представлений двоичной строки "hello" в данных IO:

[?h, "el", ["l", [?o]]]

Встроенный тип iodata/0 определяется через iolist/0. Список IO — это то же самое, что и данные IO, но он не допускает двоичную строку на верхнем уровне (но двоичные строки все еще разрешены в самом списке).

Примеры использования данных IO

Данные IO существуют потому, что часто требуется выполнить много операций добавления к меньшим фрагментам двоичных данных, чтобы создать большую двоичную строку. Однако в Erlang и Elixir конкатенация двоичных строк скопирует конкатенированные двоичные строки в новую двоичную строку.

def email(username, domain) do
  username <> "@" <> domain
end

В этой функции создание адреса электронной почты скопирует двоичные строки username и domain. Теперь представьте, что вы хотите использовать полученный адрес электронной почты внутри другой двоичной строки:

def welcome_message(name, username, domain) do
  "Welcome #{name}, your email is: #{email(username, domain)}"
end

IO.puts(welcome_message("Meg", "meg", "example.com"))
#=> "Welcome Meg, your email is: meg@example.com"

Каждый раз, когда вы конкатенируете двоичные строки или используете интерполяцию (#{}), вы создаете копии этих двоичных строк. Однако во многих случаях вам не нужна полная двоичная строка во время ее создания, а только в конце, чтобы вывести ее на печать или отправить куда-то. В таких случаях можно построить двоичную строку, создав данные IO:

def email(username, domain) do
  [username, ?@, domain]
end

def welcome_message(name, username, domain) do
  ["Welcome ", name, ", your email is: ", email(username, domain)]
end

IO.puts(welcome_message("Meg", "meg", "example.com"))
#=> "Welcome Meg, your email is: meg@example.com"

Создание данных IO обходится дешевле, чем конкатенация двоичных строк. Конкатенация нескольких фрагментов данных IO просто объединяет их в списке, поскольку данные IO могут быть произвольно вложены, а это дешёвая и эффективная операция. Большинство API, основанных на IO, такие как :gen_tcp и IO, получают данные IO и записывают их в сокет напрямую, не преобразуя их в двоичную строку.

Один недостаток данных IO заключается в том, что вы не можете выполнять такие действия, как сопоставление с образцом первой части фрагмента данных IO, как вы можете с двоичной строкой, потому что вы обычно не знаете форму данных IO. В этих случаях вам может потребоваться преобразовать их в двоичную строку, вызвав iodata_to_binary/1, что относительно эффективно, так как реализовано нативно в C. Другие функции, такие как вычисление длины данных IO, могут быть вычислены непосредственно на данных IO, вызвав iodata_length/1.

Chardata

Erlang и Elixir также имеют понятие chardata/0. Chardata очень похож на данные IO: единственное различие состоит в том, что целые числа в данных IO представляют байты, а целые числа в chardata представляют кодовые точки Юникода. Байты (byte/0) — это целые числа в диапазоне 0..255, а кодовые точки Юникода (char/0) — целые числа в диапазоне 0..0x10FFFF. Модуль IO предоставляет функцию chardata_to_string/1 для chardata в качестве «аналога» функции iodata_to_binary/1 для данных IO.

Если вы попытаетесь использовать iodata_to_binary/1 для chardata, это приведет к ошибке аргумента. Например, давайте попробуем поместить кодовую точку, которую нельзя представить одним байтом, например, ?π, в данные IO:

IO.iodata_to_binary(["The symbol for pi is: ", ?π])
#=> ** (ArgumentError) argument error

Если мы используем chardata вместо этого, это будет работать как ожидается:

iex> IO.chardata_to_string(["The symbol for pi is: ", ?π])
"The symbol for pi is: π"

Резюме

Типы

chardata()
device()
nodata()

Функции

binread(device \\ :stdio, line_or_chars)

Читает из устройства IO device. Операция не безопасна для Юникода.

binstream()

Возвращает примитивный, основанный на строках IO.Stream на :stdio. Операция не безопасна для Юникода.

binstream(device \\ :stdio, line_or_bytes)

Преобразует устройство IO device в IO.Stream. Операция не безопасна для Юникода.

binwrite(device \\ :stdio, iodata)

Записывает iodata в указанное device.

chardata_to_string(chardata)

Преобразует chardata в строку.

getn(prompt, count \\ 1)

Получает заданное количество байтов с устройства ввода-вывода :stdio.

getn(device, prompt, count)

Получает заданное количество байтов с указанного устройства IO device.

gets(device \\ :stdio, prompt)

Читает строку с устройства IO device.

inspect(item, opts \\ [])

Отображает и записывает заданный item в стандартный вывод.

inspect(device, item, opts)

Отображает item согласно заданным параметрам с использованием устройства IO device.

iodata_length(iodata)

Возвращает размер данных IO.

iodata_to_binary(iodata)

Преобразует данные IO в двоичную строку

puts(device \\ :stdio, item)

Записывает item в указанное device, аналогично write/2, но добавляет перевод строки в конце.

read(device \\ :stdio, line_or_chars)

Читает с устройства IO device.

stream()

Возвращает основанный на строках IO.Stream на :stdio.

stream(device \\ :stdio, line_or_codepoints)

Преобразует устройство IO device в IO.Stream.

warn(message)

Записывает message в stderr вместе с текущим стеком вызовов.

warn(message, stacktrace_info)

Записывает message в stderr вместе с заданным stacktrace_info.

write(device \\ :stdio, chardata)

Записывает chardata в указанное device.

END_OF_DOCUMENT_MARKER

Типы

chardata()Source

@type chardata() ::
  String.t() | maybe_improper_list(char() | chardata(), String.t() | [])

device()Source

@type device() :: atom() | pid()

nodata()Source

@type nodata() :: {:error, term()} | :eof

Функции

binread(device \\ :stdio, line_or_chars)Source

@spec binread(device(), :eof | :line | non_neg_integer()) :: iodata() | nodata()

Считывает данные из устройства ввода-вывода device. Операция небезопасна с Unicode.

Итерация по device выполняется в соответствии со значением аргумента line_or_chars:

  • если line_or_chars — целое число, оно представляет количество байтов. Устройство ввода-вывода итерируется по этому количеству байтов. Этот режим рекомендуется для чтения нетекстовых данных.

  • если line_or_chars равно :line, устройство ввода-вывода итерируется построчно. Символы перевода строки CRFL (" ") автоматически нормализуются до " ".

  • если line_or_chars равно :eof (начиная с версии 1.13), устройство ввода-вывода итерируется до конца. Если устройство уже в конце, возвращается значение :eof.

Возвращает:

  • data - выходные байты

  • :eof - обнаружен конец файла

  • {:error, reason} - другая (редкая) ошибка; например, {:error, :estale} при чтении с тома NFS

Примечание: не используйте эту функцию с устройствами ввода-вывода в режиме Unicode, так как она вернёт неверный результат.

binstream()Source

@spec binstream() :: Enumerable.t(binary())

Возвращает необработанный, основанный на строках IO.Stream на :stdio. Операция небезопасна с Unicode.

Эквивалентно:

IO.binstream(:stdio, :line)

binstream(device \\ :stdio, line_or_bytes)Source

@spec binstream(device(), :line | pos_integer()) :: Enumerable.t()

Преобразует устройство ввода-вывода device в IO.Stream. Операция небезопасна с Unicode.

IO.Stream реализует как Enumerable, так и Collectable, позволяя использовать её для чтения и записи.

Итерация по device выполняется по указанному количеству байтов или построчно, если задано :line. В случае :line, " " автоматически нормализуется до " ". Передача количества байтов рекомендуется для чтения нетекстовых данных.

Обратите внимание, что поток ввода-вывода имеет побочные эффекты, и каждый раз при работе с потоком вы можете получить разные результаты.

Это считывает данные из устройства ввода-вывода как необработанный двоичный код. Следовательно, не используйте эту функцию с устройствами ввода-вывода в режиме Unicode, так как она вернёт неверный результат.

binstream/0 была добавлена в Elixir v1.12.0, а binstream/2 доступна с версии v1.0.0.

binwrite(device \\ :stdio, iodata)Source

@spec binwrite(device(), iodata()) :: :ok

Записывает iodata в указанное устройство device.

Эта операция предназначена для использования с «сырыми» устройствами, которые запускаются без кодировки. Указанные iodata записываются в устройство без преобразования. Дополнительная информация об данных ввода-вывода приведена в разделе «Данные ввода-вывода» в документации модуля.

Используйте write/2 для устройств с кодировкой.

Важно: не используйте эту функцию с устройствами ввода-вывода в режиме Unicode, так как она запишет неверные данные. В частности, стандартное устройство ввода-вывода по умолчанию настроено на Unicode, поэтому запись в stdio с помощью этой функции, вероятно, приведёт к передаче по каналу неверных данных.

chardata_to_string(chardata)Source

@spec chardata_to_string(chardata()) :: String.t()

Преобразует chardata в строку.

Дополнительную информацию о chardata см. в разделе «Chardata» документации модуля.

В случае неудачи преобразования генерируется исключение UnicodeConversionError. Если передано строка, возвращается сама строка.

Примеры

iex> IO.chardata_to_string([0x00E6, 0x00DF])
"æß"

iex> IO.chardata_to_string([0x0061, "bc"])
"abc"

iex> IO.chardata_to_string("string")
"string"

getn(prompt, count \\ 1)Source

@spec getn(
  device() | chardata() | String.Chars.t(),
  pos_integer() | :eof | chardata() | String.Chars.t()
) :: chardata() | nodata()

Считывает определённое количество байтов с устройства ввода-вывода :stdio.

Если устройство ввода-вывода :stdio — устройство Unicode, то count подразумевает количество точек кодирования Unicode для извлечения. В противном случае, count — количество извлекаемых байтов.

См. IO.getn/3 для описания возвращаемых значений.

getn(device, prompt, count)Source

@spec getn(device(), chardata() | String.Chars.t(), pos_integer() | :eof) ::
  chardata() | nodata()

Считывает определённое количество байтов с устройства ввода-вывода device.

Если устройство ввода-вывода device — устройство Unicode, то count подразумевает количество точек кодирования Unicode для извлечения. В противном случае, count — количество извлекаемых байтов.

Возвращает:

  • data - введённые символы

  • :eof - обнаружен конец файла

  • {:error, reason} - другая (редкая) ошибка; например, {:error, :estale} при чтении с тома NFS

gets(device \\ :stdio, prompt)Source

@spec gets(device(), chardata() | String.Chars.t()) :: chardata() | nodata()

Считывает строку с устройства ввода-вывода device.

Возвращает:

  • data - символы в строке, завершённые символом перевода строки (LF) или концом файла (EOF)

  • :eof - обнаружен конец файла

  • {:error, reason} - другая (редкая) ошибка; например, {:error, :estale} при чтении с тома NFS

Примечание: gets — сокращение для get string.

Примеры

Чтобы отобразить «Каково ваше имя?» в качестве подсказки и дождаться ввода пользователя:

IO.gets("What is your name?\n")

inspect(item, opts \\ [])Source

@spec inspect(
  item,
  keyword()
) :: item
when item: var

Выводит информацию об указанном item в стандартный вывод.

Обратите внимание, что оно возвращает исходное item без изменений. Это позволяет «отслеживать» значения, вставляя вызов IO.inspect/2 практически в любом месте кода, например, в середине конвейера.

По умолчанию используется красивое форматирование с шириной 80 символов. Ширину можно изменить, явно передав опцию :width.

Вывод может быть помечен меткой, передав опцию :label для лёгкого отличия от других вызовов IO.inspect/2. Метка выводится перед проверяемым item.

См. Inspect.Opts для полного списка оставшихся параметров форматирования. Чтобы вывести данные в другие устройства ввода-вывода, см. IO.inspect/3

Примеры

IO.inspect(<<0, 1, 2>>, width: 40)

Выводит:

<<0, 1, 2>>

Можно использовать опцию :label для добавления метки к выводу:

IO.inspect(1..100, label: "a wonderful range")

Выводит:

a wonderful range: 1..100

Опция :label особенно полезна в конвейерах:

[1, 2, 3]
|> IO.inspect(label: "before")
|> Enum.map(&(&1 * 2))
|> IO.inspect(label: "after")
|> Enum.sum()

Выводит:

before: [1, 2, 3]
after: [2, 4, 6]

inspect(device, item, opts)Source

@spec inspect(device(), item, keyword()) :: item when item: var

Выводит информацию о item в соответствии с заданными параметрами с помощью устройства ввода-вывода device.

См. inspect/2 для полного списка параметров.

iodata_length(iodata)Source

@spec iodata_length(iodata()) :: non_neg_integer()

Возвращает размер данных ввода-вывода.

Дополнительная информация о данных ввода-вывода приведена в разделе «Данные ввода-вывода» в документации модуля.

Встроенная компилятором.

Примеры

iex> IO.iodata_length([1, 2 | <<3, 4>>])
4

iodata_to_binary(iodata)Source

@spec iodata_to_binary(iodata()) :: binary()

Преобразует данные IO в двоичный формат

Операция небезопасна для Unicode.

Обратите внимание, что эта функция обрабатывает целые числа в предоставленных данных IO как сырые байты и не выполняет никаких преобразований кодирования. Если вам нужно преобразовать список символов в строку, закодированную в UTF-8, используйте chardata_to_string/1 вместо этого. Дополнительную информацию о данных IO и chardata см. в разделе «Данные IO» документации модуля.

Если эта функция получает двоичное значение, возвращается то же самое двоичное значение.

Компилятор оптимизирует эту функцию.

Примеры

iex> bin1 = <<1, 2, 3>>
iex> bin2 = <<4, 5>>
iex> bin3 = <<6>>
iex> IO.iodata_to_binary([bin1, 1, [2, 3, bin2], 4 | bin3])
<<1, 2, 3, 1, 2, 3, 4, 5, 4, 6>>

iex> bin = <<1, 2, 3>>
iex> IO.iodata_to_binary(bin)
<<1, 2, 3>>

puts(device \\ :stdio, item)Source

@spec puts(device(), chardata() | String.Chars.t()) :: :ok

Записывает item в указанное device, аналогично write/2, но добавляет перевод строки в конце.

По умолчанию device — это стандартный вывод. Возвращает :ok в случае успеха.

Примечание: puts — это сокращение для put string.

Примеры

IO.puts("Hello World!")
#=> Hello World!

IO.puts(:stderr, "error")
#=> error

read(device \\ :stdio, line_or_chars)Source

@spec read(device(), :eof | :line | non_neg_integer()) :: chardata() | nodata()

Читает из устройства IO device.

Устройство перебирается в соответствии с аргументом line_or_chars:

  • Если line_or_chars — целое число, оно представляет количество байтов. Устройство перебирается по этому количеству байтов. Этот режим предпочтительнее для чтения нетекстовых данных.

  • Если line_or_chars равно :line, устройство перебирается по строкам. Переводы строк CRFL (" ") автоматически нормализуются до " ".

  • Если line_or_chars равно :eof (с версии 1.13), устройство перебирается до тех пор, пока не достигнет конца. Если устройство уже в конце, возвращается :eof.

Возвращает:

  • data — прочитанные символы

  • :eof — достигнут конец файла

  • {:error, reason} — другая (редкая) ошибка; например, {:error, :estale} при чтении с NFS-тома

stream()Source

@spec stream() :: Enumerable.t(String.t())

Возвращает основанный на строках IO.Stream для :stdio.

Это эквивалентно:

IO.stream(:stdio, :line)

stream(device \\ :stdio, line_or_codepoints)Source

@spec stream(device(), :line | pos_integer()) :: Enumerable.t()

Преобразует устройство IO device в IO.Stream.

IO.Stream реализует как Enumerable, так и Collectable, что позволяет использовать его для чтения и записи.

Устройство перебирается по указанному количеству символов или по строкам, если :line. В случае :line переводы строк " " автоматически нормализуются до " ".

Чтение выполняется в формате UTF-8. Обратитесь к IO.binstream/2 для обработки IO как сырого двоичного значения.

Обратите внимание, что потоки IO имеют побочные эффекты, и при каждом переборе вы можете получить разные результаты.

stream/0 был добавлен в Elixir v1.12.0, а stream/2 — с v1.0.0.

Примеры

Вот пример того, как эмулировать сервер эха из командной строки:

Enum.each(IO.stream(:stdio, :line), &IO.write(&1))

Еще один пример, где вам может потребоваться собирать ввод пользователя каждую новую строку и прерывать на пустой строке, после чего удалить лишние символы новой строки ("\n"):

IO.stream(:stdio, :line)
|> Enum.take_while(&(&1 != "\n"))
|> Enum.map(&String.replace(&1, "\n", ""))

warn(message)Source

@spec warn(chardata() | String.Chars.t()) :: :ok

Выводит message в stderr вместе с текущим трассировкой стека.

Возвращает :ok в случае успеха.

Не вызывайте эту функцию в конце другой функции. Из-за оптимизации хвостовой рекурсии запись в трассировку стека не будет добавлена, и трассировка стека будет неправильно обрезана. Поэтому убедитесь, что по крайней мере одно выражение (или атом, например, :ok) следует за вызовом IO.warn/1.

Примеры

IO.warn("variable bar is unused")
#=> warning: variable bar is unused
#=>   (iex) evaluator.ex:108: IEx.Evaluator.eval/4

warn(message, stacktrace_info)Source

@spec warn(
  chardata() | String.Chars.t(),
  Exception.stacktrace() | keyword() | Macro.Env.t()
) :: :ok

Выводит message в stderr вместе с указанной stacktrace_info.

stacktrace_info должно быть одним из:

  • атомом, где все записи трассировки стека будут включены в сообщение об ошибке

  • структурой Macro.Env (с версии 1.14.0), где используется единственная запись трассировки стека из среды компиляции

  • списком ключевых слов, включающим по крайней мере опцию :file, представляющую единственную запись трассировки стека (с версии 1.14.0). Также поддерживаются опции :line, :column, :module, и :function

Эта функция уведомляет компилятор о выводе предупреждения и генерирует диагностическое сообщение компилятора (Code.diagnostic/1). Диагностическое сообщение будет содержать точную информацию о файле и местоположении, если указана структура Macro.Env или эти значения переданы как список ключевых слов, но не для трассировок стека, так как они часто неточны.

Возвращает :ok в случае успеха.

Примеры

IO.warn("variable bar is unused", module: MyApp, function: {:main, 1}, line: 4, file: "my_app.ex")
#=> warning: variable bar is unused
#=>   my_app.ex:4: MyApp.main/1

write(device \\ :stdio, chardata)Source

@spec write(device(), chardata() | String.Chars.t()) :: :ok

Записывает chardata в указанное device.

По умолчанию device — это стандартный вывод.

Примеры

IO.write("sample")
#=> sample

IO.write(:stderr, "error")
#=> error

Download ePub version

Built using ExDoc (v0.36.1) for the Elixir programming language

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.18.1/IO.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API