پر

پروتکل در Elixir

4 تمرین

درباره‌ی پروتکل

پروتکل‌ها عبارت‌اند از:

  • سازوکاری برای دستیابی به چندریختی.
  • تعریف‌شده با defprotocol.
  • پیاده‌سازی‌شده برای یک نوع داده‌ی مشخص با defimpl.

یکی از نقاط قوت بزرگ پروتکل‌ها این است که پیاده‌سازی یک پروتکل برای یک نوع داده‌ی مشخص لازم نیست در کنار تعریف آن نوع داده یا تعریف خود پروتکل قرار بگیرد. این امکان را فراهم می‌کند که کتابخانه‌هایی نوشته شود که کاربرانشان بتوانند به‌راحتی آن‌ها را گسترش دهند تا با انواع داده‌ی سفارشی خودشان کار کنند، بدون اینکه نیازی به تغییر کتابخانه داشته باشند.

پیاده‌سازی

می‌توان پروتکل‌ها را برای همه‌ی انواع Elixir پیاده‌سازی کرد: Tuple، Atom، List، BitString، Integer، Float، Function، PID، Map، Port، Reference، Any و ساختارها.

می‌توان پروتکل‌ها را برای چندین نوع به‌طور همزمان پیاده‌سازی کرد:

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 از این پروتکل برای درج یک enumerable در یک مجموعه استفاده می‌کند.
  • Inspect - می‌توانید این پروتکل را پیاده‌سازی کنید تا نحوه‌ی نمایش یک نوع داده‌ی مشخص به‌صورت رشته توسط Kernel.inspect/2 را تغییر دهید.
  • String.Chars - می‌توانید این پروتکل را پیاده‌سازی کنید تا نحوه‌ی نمایش یک نوع داده‌ی مشخص به‌صورت رشته توسط Kernel.to_string/1 را تغییر دهید.
ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

پروتکل را یاد بگیرید

تمرین کردن قفل شده است

برای تمرین پروتکل قفل 1 تمرین دیگر را باز کنید