البروتوكولات هي:
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 نوع بيانات معيّنًا على هيئة سلسلة نصية.