Подтвердить что ты не робот

Как использовать ключевое слово "с" в Elixir и для чего оно предназначено?

В elixir 1.2 они включили ключевое слово "с", но мне не совсем понятно, для чего он предназначен.

Как и в какой ситуации я буду использовать его?

4b9b3361

Ответ 1

В версиях Elixir до 1.2 при использовании функций в конвейере вам нужно будет либо использовать библиотеку monad или инструкции для случая гнезда (которые могут быть реорганизованы с использованием частных функций, но все равно в конечном итоге будут подробными). with/1 позволяет по-другому решить эту проблему.

Вот пример из оригинального предложения:

case File.read(path) do
  {:ok, binary} ->
    case :beam_lib.chunks(binary, :abstract_code) do
      {:ok, data} ->
        {:ok, wrap(data)}
      error ->
        error
    end
  error ->
    error
end

Вот то же самое, что реорганизовано для использования функций:

path
|> File.read()
|> read_chunks()
|> wrap()

defp read_chunks({:ok, binary}) do
  {:ok, :beam_lib.chunks(binary, :abstract_code)}
end
defp read_chunks(error), do: error

defp wrap({:ok, data}) do
  {:ok, wrap(data)}
end
defp wrap(error), do: error

И тот же код с помощью with:

with {:ok, binary} <- File.read(path),
     {:ok, data} <- :beam_lib.chunks(binary, :abstract_code),
     do: {:ok, wrap(data)}

Это работает, потому что with будет сохранять цепочку только в том случае, если значение соответствует шаблону слева. Если нет, цепочка прерывается и возвращается первый результат несогласования. Например, если файл не существует, то File.read(path) вернет {:error, :enoent} - это не соответствует {:ok, binary}, поэтому вызов with/1 вернет {:error, :enoent}.

Стоит отметить, что с может использоваться с любым шаблоном, а не только {:ok, foo} и {:error, reason} (хотя это очень распространенный вариант использования).

Ответ 2

Вы также можете связать "голые выражения", как сообщает doc:

with {:ok, binary} <- File.read(path),
     header = parse_header(binary),
     {:ok, data} <- :beam_lib.chunks(header, :abstract_code),
     do: {:ok, wrap(data)}

Переменная header будет доступна только внутри оператора with. Дополнительная информация на https://gist.github.com/josevalim/8130b19eb62706e1ab37