Как вы сопоставляете ноль или пустую строку в эликсире? - PullRequest
0 голосов
/ 24 сентября 2018

Вот пример кода с тестами, где у меня есть функция, которая проверяет, находится ли переданное значение в допустимом наборе значений, и если это не так, то возникает исключение, но если переданное значение равно nil илипустая строка, она просто возвращает false.Идея здесь в том, что любое пустое значение означает, что нет значения.Если есть непустое значение, которое не соответствует ни одному из допустимых значений, то мы хотим вызвать исключение, потому что это значение недопустимо.Также представьте, что это значение исходит из аргумента командной строки или параметра запроса Phoenix, где мы не можем контролировать входное значение равным просто nil, мы должны проверить все перестановки пустого значения, nil, пустой строки или строки, содержащей толькопробелы.

ExUnit.start()

defmodule ValidColor do
  @valid_colors MapSet.new(~w[red green blue])

  def valid?(color) do
    cond do
      blank?(color) -> false
      MapSet.member?(@valid_colors, color) -> true
      true -> raise "invalid color"
    end
  end

  defp blank?(value) do
    case value do
      nil -> true
      v when is_binary(v) -> v =~ ~r/\A\s*\z/
      _ -> false
    end
  end
end

defmodule ValidColorTest do
  use ExUnit.Case, async: true

  test "nil" do
    refute ValidColor.valid?(nil)
  end

  test "empty string" do
    refute ValidColor.valid?("")
  end

  test "string with only blank characters" do
    refute ValidColor.valid?("     ")
  end

  test "invalid color" do
    assert_raise RuntimeError, "invalid color", fn ->
      ValidColor.valid?("yellow")
    end
  end

  test "valid color" do
    assert ValidColor.valid?("red")
  end
end

Это похоже на случай, когда полезна вспомогательная функция blank?, как я сделал в этом примере.Кажется, среди программистов Elixir есть чувство, что этот тип вспомогательного метода не нужен и может быть выполнен с помощью сопоставления с шаблоном .

Как вы можете реализовать подобную функцию с помощью простого сопоставления с шаблоном ине вспомогательная функция blank?? 1010 *

Ответы [ 4 ]

0 голосов
/ 25 сентября 2018

Хотя все ответы, приведенные здесь, как-то верны, они не являются семантически идеальными.На самом деле вы хотите обработать nil как пустую строку и отклонить ее.Сделайте это просто:

defp blank?(str_or_nil),
  do: "" == str_or_nil |> to_string() |> String.trim()

Обратите внимание, что это решение, в отличие от других приведенных здесь, до сих пор работает с всеми пробелами, определенными как пробелы в спецификации UTF-8.

0 голосов
/ 24 сентября 2018

Случай nil прост:

defp blank?(nil), do: true

Чтобы проверить, состоит ли строка только из пробельных символов, требуется более сложное сопоставление с образцом:

# Empty string is always blank.
defp blank?(""), do: true

# If the string's first byte is a space, tab, newline, or carriage return,
# we recursively check the remaining part of the string.
defp blank?(<<h, t::binary>>) when h in ' \t\n\r', do: blank?(t)

# Otherwise, it's not blank.
defp blank?(_), do: false
0 голосов
/ 24 сентября 2018

Вы также можете использовать case/2:

def blank?(str) do
  case str do
    nil -> true
    "" -> true
    " " <> r -> blank?(r)
    _ -> false 
  end
end

NB: в этом случае мы рассматриваем только пробелы, сопоставление с образцом для "\ n", "\ r" и"\ t" также следует рассматривать как @dogbert в своем ответе.

0 голосов
/ 24 сентября 2018

Функции Elixir могут иметь несколько функциональных головок.При этом довольно просто создать вспомогательную функцию blank?/1.

defp blank?(nil), do: false
defp blank?(""), do: false
defp blank?(_), do: true
...