Эликсир: Шаблон соответствует списку определенного типа? - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть список структур произвольного размера.

Давайте назовем его l.

l = [%X{a:1}, %X{a:3}, %X{a:9}, %X{a:11}]

Размер l постоянно меняется,Что я хотел бы знать, так это как сопоставить шаблон с l, чтобы он всегда состоял из структур %X{}.Я хочу, чтобы поиск по шаблону не удался, если в списке есть что-то еще.Например:

l = [%X{a:1}, %X{a:3}, %Y{a:9}, %Z{a:11}]

То, что я пробовал

i = %X{}
j = %Y{}

[%X{}|_] = [i,i,i]

Но это соответствует только первому элементу.

[%X{}|_] = [i,j,j]

Должен произойти сбой в моем случае использования, но это не так.Возможно, если есть оператор или что-то вроде этого, которое будет соответствовать списку определенного типа, это именно то, что я ищу:

[%X{}+] = [i,i,i] # Doesn't exist, just an example

Какой-то фон

Я нахожусь на Фениксе, и у меня есть модель post с has_many отношениями с images.Данный пользователь может загрузить несколько изображений, и я хотел бы сопоставить шаблон, чтобы убедиться, что я работаю с правильной структурой (%Plug.Upload{}) в этом случае.

Любая помощь очень ценится.Спасибо:)

Ответы [ 4 ]

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

Как я решил это:

Как описано в моем вопросе, я пытался сопоставить каждый экземпляр загруженного файла, чтобы убедиться, что это %Plug.Upload{} структура. Я должен был упомянуть, что я нахожусь на Фениксе. Хорошая вещь в Phoenix заключается в том, что вы можете добавить этот вид проверки непосредственно в свои модели - для этого нужны наборы изменений и их проверки! И они будут проверяться автоматически для каждого экземпляра модели, сохраняемой в базе данных.

Итак, я добавил собственную модель проверки в image.ex модели.

Итак, моя ревизия в итоге выглядела так:

  @doc false
  def changeset(image, attrs) do
    image
    |> cast(attrs, [:title, :description, :alt, :src, :sequence, :file])
    |> ensure_valid_upload()
    |> validate_required([:file])
  end

Сказав это, я также использовал принятый ответ в других областях моего кода, которые не имели прямого отношения к моим моделям.

Надеюсь, это поможет кому-то в будущем.

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

Вы не можете использовать сопоставление с образцом для каждого элемента списка (без рекурсии).В этом случае я бы использовал Enum.all?/2 и макрос match?/2:

if Enum.all?(list, &match?(%X{}, &1)) do
  ...
end
0 голосов
/ 18 сентября 2018

Хотя ответ @Dogbert совершенно верен, я лично нахожу более четкие предложения более краткими:

all_are_x =
  Enum.all?(list, fn
    %X{} -> true
    _ -> false
  end)
0 голосов
/ 18 сентября 2018

AFAIK, то, что вы ищете, не существует: вы не можете сопоставить шаблон с каждым элементом списка.

Вы можете использовать Enum.map / 2 для сбоя припервый не %X{} элемент:

Enum.map(l, &(%X{}=&1))

Для сопоставления с образцом я использовал: %X{} = something, а Догберт использовал: match?(%X{}, &1)

Разница в том, что первыйтерпит неудачу, если это не совпадает, в то время как второй возвращает false.Если вы хотите придерживаться " let it crash " эликсира, вас может заинтересовать первый, хотя в большинстве случаев вы предпочитаете использовать второй, например, такой:

k == Enum.reject(l, &match?(%X{}=&1))
k == [] || IO.inspect(k)

Enum.reject? / 2 , используемый с match? / 2 , не завершится сбоем и вернет список всех элементов, которые не являются X-структурой.

...