المسارات
/
Elixir
Elixir
/
المنهج
/
البروتوكولات
ال

البروتوكولات في Elixir

4 تمارين

نبذة عن البروتوكولات

البروتوكولات هي:

  • آلية لتحقيق تعدد الأشكال.
  • تُعرَّف باستخدام defprotocol.
  • تُنفَّذ لنوع بيانات معيّن باستخدام defimpl.

من أكبر مزايا البروتوكولات أن تنفيذ بروتوكولٍ ما لنوع بيانات معيّن لا يلزم أن يُرفَق مع تعريف نوع البيانات ولا مع تعريف البروتوكول. وهذا يتيح كتابة مكتبات يستطيع مستخدموها توسيعها بسهولة لتتعامل مع أنواع البيانات المخصّصة التي يستخدمونها، دون الحاجة إلى تعديل المكتبة.

التنفيذ

من الممكن تنفيذ البروتوكولات لجميع أنواع Elixir: Tuple، وAtom، وList، وBitString، وInteger، وFloat، وFunction، وPID، وMap، وPort، وReference، وAny، والبنى (structs).

يمكن تنفيذ البروتوكولات لعدة أنواع في وقت واحد:

defimpl Reversible, for: [Map, List] do
  def reverse(term) do
    Enum.reverse(term)
  end
end

عند تنفيذ بروتوكول لبنية مباشرةً داخل الوحدة التي تعرّفها، يمكن حذف الوسيط :for:

defmodule ShoppingCart do
  defstruct [:items]

  defimpl Reversible do
    def reverse(shopping_cart) do
      Enum.reverse(shopping_cart)
    end
  end
end

الرجوع الاحتياطي إلى Any

بشكل افتراضي، يؤدي استدعاء بروتوكول لنوع بيانات لم يُنفَّذ من أجله إلى رفع خطأ Protocol.UndefinedError:

to_string({})
# => ** (Protocol.UndefinedError) protocol String.Chars not implemented for {} of type Tuple
#        (elixir 1.10.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
#        (elixir 1.10.3) lib/string/chars.ex:22: String.Chars.to_string/1

يمكن تجنّب ذلك بتوفير تنفيذ احتياطي يُستخدَم في مثل هذه الحالة. لفعل ذلك، اضبط سمة الوحدة @fallback_to_any على true عند تعريف البروتوكول، واكتب تنفيذًا للنوع Any:

defprotocol Reversible do
  @fallback_to_any true
  def reverse(term)
end

defimpl Reversible, for: Any do
  def reverse(term) do
    term
  end
end

لاحظ أنه في معظم الحالات يكون رفع خطأ هو الأسلوب المفضّل، لأنه من الصعب افتراض سلوك معقول لبروتوكولٍ يشمل جميع أنواع البيانات.

بروتوكولات مدمجة جديرة بالملاحظة

  • Enumerable - دوال الوحدتين Enum وStream تعمل مع أنواع البيانات التي تنفّذ هذا البروتوكول.
  • Collectable - تستخدم الدالة Enum.into/2 هذا البروتوكول لإدراج قيمة قابلة للتعداد في مجموعة.
  • Inspect - يمكنك تنفيذ هذا البروتوكول لتغيير الطريقة التي تمثّل بها Kernel.inspect/2 نوع بيانات معيّنًا على هيئة سلسلة نصية.
  • String.Chars - يمكنك تنفيذ هذا البروتوكول لتغيير الطريقة التي تمثّل بها Kernel.to_string/1 نوع بيانات معيّنًا على هيئة سلسلة نصية.
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة

تعلّم البروتوكولات

التدريب مقفل

افتح 1 تمرين إضافي لممارسة البروتوكولات