كل من جاء إلى Elixir / Erlang من لغات أخرى ، على الأرجح ، لديه بعض التوقعات حول كيفية عمل عوامل المقارنة >
، <
، ==
، وما إلى ذلك. يتوقع المرء أن 1 < 2
، (وهذا هو حقًا لذلك). من حيث المبدأ ، يمكننا القول أن المقارنة تعمل كما ينبغي. لكن ليس دائما.
في Elixir / Erlang ، يمكنك مقارنة أي شيء. عموما. بينما بالنسبة لمعاملين من نفس النوع ، فإن النتيجة ليست مثبطة ، كما في المثال أعلاه ، تؤدي مقارنة عاملين من الأنواع المختلفة إلى عواقب غير متوقعة إلى حد ما. لأن الأنواع نفسها "مرتبة للمقارنة". بهذه الطريقة:
number < atom < reference < function < port < pid < tuple < map < list < bitstring
الأمر الذي يؤدي فجأة إلى حقيقة أن المقارنة المشروعة تمامًا 42 < nil
تُرجع إلى الحقيقة.
بالإضافة إلى ذلك ، تتم مقارنة maps
(ونتيجة لذلك ، structs
، والتي هي في الواقع نفس maps
تحت الغطاء) وفقًا لحقولها بالترتيب الأبجدي. بمعنى آخر ، ستتم مقارنة التواريخ (التي يتم تنفيذها في Elixir بواسطة بنية Date
) بالتتابع بقيم day
، ثم month
، ثم حقول year
، وهذا ، على الأرجح ، ليس كما نود تمامًا.
بدءًا من Enum.sort/2
، يوفر Elixir عملية فرز مريحة باستخدام Enum.sort/2
القياسي ، إذا كان الهيكل يقوم بتصدير وظيفة compare/2
:
defmodule User do defstruct [:name] def compare(%User{name: n1}, %User{name: n2}) when n1 < n2, do: :lt def compare(%User{name: n1}, %User{name: n2}) when n1 > n2, do: :gt def compare(%User{}, %User{}), do: :eq end users = [ %User{name: "john"}, %User{name: "joe"}, %User{name: "jane"} ] Enum.sort(users, {:asc, User})
يمكن تمرير أي وحدة نمطية تحدد بنية وتقوم بتصدير وظيفة compare/2
كمعلمة ثانية لاستدعاء Enum.sort/2
إما كما هي أو ك tuple {:asc | :desc, StructModule}
{:asc | :desc, StructModule}
. Enum.sort/2
ذكيًا بما يكفي compare/2
للوحدة النمطية التي تم تمريرها إلى Enum.sort/2
. فيما يلي مقتطف من وحدة Enum
التي تنفذ هذه الوظيفة المعينة:
... defp to_sort_fun(module) when is_atom(module), do: &(module.compare(&1, &2) != :gt) defp to_sort_fun({:asc, module}) when is_atom(module), do: &(module.compare(&1, &2) != :gt) defp to_sort_fun({:desc, module}) when is_atom(module), do: &(module.compare(&1, &2) != :lt)
يتيح لك ذلك فرز التواريخ في المثال أدناه بشكل صحيح (بفضل Date.compare/2
الموجود) ، وكذلك أي بنية معرفة من قبل المستخدم (إذا كانت تصدر compare/2
، بالطبع) ، كما في المثال مع بنية User
أعلاه.
dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]] Enum.sort(dates)
فرز جيد!