مسیرها
/
Elixir
Elixir
/
تمرین‌ها
/
زیرریزی پشته
زیرریزی پشته

زیرریزی پشته

تمرین یادگیری

مقدمه

استثنا

همه‌ی خطاها در Elixir «رفتار استثنا» را پیاده‌سازی می‌کنند. «رفتار استثنا» درست مانند «رفتار دسترسی»، توابع کالبکی را تعریف می‌کند که یک ماژول برای ایفای قرارداد نرم‌افزاری این رفتار باید پیاده‌سازی کند. وقتی یک خطا تعریف می‌شود، ویژگی‌های زیر را دارد:

  • اسم ماژول، اسم خطا را تعیین می‌کند.
  • ماژول یک ساختار خطا تعریف می‌کند.
  • این ساختار یک فیلد :message خواهد داشت.
  • می‌توان از ماژول همراه با raise/1 و raise/2 برای raise کردن خطای مورد نظر استفاده کرد.

«رفتار استثنا» همچنین دو تابع کالبک را مشخص می‌کند: message/1 و exception/1. اگر پیاده‌سازی نشوند، از پیاده‌سازی‌های پیش‌فرض استفاده می‌شود. message/1 هنگام فراخوانی با raise، ساختار خطا را به یک پیام خوانا تبدیل می‌کند. exception/1 امکان می‌دهد هنگام فراخوانی با raise/2، زمینه‌ی بیشتری به پیام اضافه شود.

تعریف یک استثنا

برای تعریف یک استثنا از یک ماژول خطا، از ماکروی defexception استفاده می‌کنیم:

# Defines a minimal error, with the name `MyError`
defmodule MyError do
  defexception message: "error"
end

# Defines an error with a customized exception/1 function
defmodule MyCustomizedError do
  defexception message: "custom error"

  @impl true
  def exception(value) do
    case value do
      [] ->
        %MyCustomizedError{}

      _ ->
        %MyCustomizedError{message: "Alert: " <> value}
    end
  end
end

استفاده از استثنا

از خطاهای تعریف‌شده می‌توان مانند یک خطای داخلی و با raise/1 یا raise/2 استفاده کرد.

  • raise/1 یک خطای مشخص را با اسم ماژولش raise می‌کند، یا اگر آرگومان یک رشته باشد، یک RuntimeError را با آن رشته به عنوان پیام raise می‌کند.
  • raise/2 یک خطای مشخص را با اسم ماژولش raise می‌کند و یک آرگومان ویژگی‌ها می‌پذیرد که برای به دست آوردن خطا با پیام مناسب به کار می‌رود.

دستورالعمل‌ها

در حالی که کار خود را در Instruments of Texas ادامه می‌دهید، پیشرفتی در پیاده‌سازی ماشین‌حساب RPN با Elixir در حال انجام است. تیم شما می‌خواهد بتواند خطاهایی اختصاصی‌تر از خطاهای عمومی کتابخانه‌ی استاندارد ایجاد کند. شما در حال تحقیق هستید، اما تصمیم گرفته‌اید دو خطای جدید بنویسید که Exception Behaviour را پیاده‌سازی می‌کنند.

1. خطا برای تقسیم بر صفر

تقسیم یک عدد بر صفر نتیجه‌ی تعریف‌نشده‌ای تولید می‌کند که به نظر تیم بهتر است با یک خطا نشان داده شود.

ماژول DivisionByZeroError را طوری پیاده‌سازی کنید که پیام خطایش "division by zero occurred" باشد.

raise DivisionByZeroError
# => ** (DivisionByZeroError) division by zero occurred

2. خطا هنگام برخورد با کمبود پشته

ماشین‌حساب‌های RPN از یک «پشته» استفاده می‌کنند تا اعداد را پیش از انجام محاسبات روی آن‌ها نگه دارند. تیم این «پشته» را با فهرستی از اعداد (صحیح و اعشاری) نمایش می‌دهد، مثلاً: [3, 4.0]. هر عملیات برای انجام محاسبه‌اش به تعداد مشخصی عدد روی پشته نیاز دارد. وقتی اعداد کافی روی پشته نباشد، به این حالت خطای «کمبود پشته» می‌گویند. استثنای StackUnderflowError را پیاده‌سازی کنید که یک پیام پیش‌فرض و زمینه‌ی اضافی اختیاری فراهم می‌کند.

raise StackUnderflowError
# => ** (StackUnderflowError) stack underflow occurred

raise StackUnderflowError, "when dividing"
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing

3. یک تابع تقسیم بنویسید

تابع divide/1 را پیاده‌سازی کنید که یک پشته (فهرستی از دو عدد) می‌گیرد و:

  • وقتی پشته اعداد کافی ندارد، خطای کمبود پشته را ایجاد می‌کند
  • وقتی مقسوم‌علیه ۰ است، خطای تقسیم بر صفر را ایجاد می‌کند (توجه کنید که فهرست اعداد به ترتیب معکوس ذخیره می‌شود)
  • وقتی خطایی ایجاد نمی‌شود، تقسیم را انجام می‌دهد
RPNCalculator.Exception.divide([])
# => ** (StackUnderflowError) stack underflow occurred, context: when dividing

RPNCalculator.Exception.divide([0, 100])
# => ** (DivisionByZeroError) division by zero occurred

RPNCalculator.Exception.divide([4, 16])
# => 4

توجه کنید که ترتیب فهرست معکوس است!

ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Elixir Exercism

آماده‌اید زیرریزی پشته را شروع کنید؟

در Exercism ثبت‌نام کنید تا Elixir را همراه با 58 مفهوم168 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.