2 ماه پیش
با مفهوم اینترفیس آشنا میشیم و یاد میگیریم چطور از اینترفیس در زبان GO استفاده کنیم.
اینترفیس در برنامهنویسی یک قرارداد یا الگوست که مشخص میکند چه متدهایی باید توسط یک نوع (type) پیادهسازی شوند، بدون اینکه جزئیات پیادهسازی را مشخص کند.
اینترفیس در اصل رفتار (behavior) یا قابلیتهایی که یک شی باید داشته باشد را توصیف میکند.
در زبان Go، اینترفیسها نوعی داده (type) هستند که فقط امضای متدها را تعریف میکنند و هیچ پیادهسازی ندارند.
در گولنگ پیاده سازی اینترفیس ها به صورت ضمنی انجام میشود بدین معنی که اگر یک type تمام متدهای تعریف شده در یک interface رو داشته باشه، اون interface رو پیادهسازی کرده است.
در مثال زیر File بهطور خودکار Writer را پیادهسازی کرده است زیرا تمامی متدهای آن را دارد:
type assertion یا interface assertion مکانیزمی است که به توسعهدهنده امکان میدهد تا از یک مقدار با نوع interface، نوع واقعی (concrete type) آن را استخراج کنند.
سینتکس کلی type assertion به صورت زیر است:
i
یک مقدار از نوع interface
است.
T
نوعی است که انتظار داریم مقدار i
واقعاً از آن نوع باشد.
value
متغیری است که مقدار استخراجشده با نوع T
در آن ذخیره میشود.
اگر مقدار i واقعاً از نوع T باشد، عملیات موفقیتآمیز خواهد بود. در غیر این صورت، برنامه دچار panic خواهد شد.
برای جلوگیری از بروز panic و بررسی ایمن نوع مقدار، میتوان از فرم دوم type assertion استفاده کرد:
اگر مقدار i
از نوع T
باشد، متغیر ok
مقدار true
خواهد داشت.
در غیر این صورت، ok
برابر false
بوده و value
مقدار صفر نوع T
را خواهد داشت.
این الگو در Go به عنوان comma-ok idiom شناخته میشود و راهکاری رایج برای انجام type assertion به صورت ایمن است.
حالا بیاید یکسری مثال واقعی رو بررسی کنیم:
همچنین اگر interface سفارشی خودتون رو درست کرده باشید میتونید به مشابه عمل کنید:
در مثال بالا در تابع DescribeShape از type assertion استفاده کردیم.
Type assertion همچنین برای بررسی اینکه آیا یک مقدار، پیادهساز یک اینترفیس خاص است یا خیر نیز کاربرد دارد. در این روش باید نوع متغیر خود را از نوع interface تعریف کنیم یا اینکه با type conversion آن را به نوع interface
تبدیل کنیم و سپس مقدار مورد نظر خودمون رو درون این متغیر قرار دهیم و در نهایت با type assertion بررسی کنیم که آیا این دیتا تایپ اینترفیس مورد نظر ما را پیاده سازی میکند یا نه. به مثال زیر دقت کنید:
برای بررسی نوع واقعی یک مقدار که از نوع interface است، علاوه بر type assertion، میتوان از type switch استفاده کرد.
اینترفیس خالی interface{}
به معنای "هر نوعی" است. چون هیچ متدی ندارد، تمام انواع در Go بهطور پیشفرض آن را پیادهسازی میکنند.
اینترفیس خالی میتواند هر نوع دیتایی را در خود جای دهد به همین دلیل در جایی که نیاز دارید تا هر نوع دیتایی را بتوانید دریافت کنید میتوانید از اینترفیس خالی استفاده کنید.
در گولنگ 1.18
نوع any به زبان اضافه شده و در واقع فقط یک نام مستعار (alias) برای interface{}
است، اما باعث میشود کد خواناتر به نظر برسد.
any مانند یک نام بهتر برای interface{}
است که کد را خوانا تر میکند.
اینترفیس خالی interface{}
نوعی از نوعزدایی (type erasure) است، یعنی نوع واقعی مخفی میشود و برای استفاده دوباره باید از type assertion یا type switch استفاده کرد.
استفاده بیش از حد یا بیدلیل از interface{}
باعث میشود کد خوانایی و ایمنی نوع خود را از دست بدهد زیرا در هنگام توسعه کد نیاز داریم تا کدهای قدیمی تر چک شود تا مطمئن شویم چه نوع داده ای به اینترفیس پاس داده شده است.
در Go، به جای ارثبری (inheritance)، از کامپوزیشن (Composition) برای ساختن ساختارها و اینترفیسهای پیچیدهتر استفاده میشود. بدین صورت میتوان چندین اینترفیس را با هم ترکیب کرد و یک اینترفیس بزرگتر ساخت.
فرض کنید دو اینترفیس مجزا داریم:
حالا میخواهیم اینترفیس جدیدی بسازیم که هم Read
و هم Write
داشته باشد:
در اینجا ReadWriter
یک کامپوزیشن از Reader
و Writer
است. هر تایپی (type) که هم Reader
و هم Writer
رو پیادهسازی کنه، ReadWriter
رو هم پیادهسازی کرده است.
در Go توصیه میشود به جای طراحی اینترفیسهای بزرگ، اینترفیسهای کوچک با یک یا دو متد طراحی شوند و در صورت نیاز با کامپوزیشن آنها را ترکیب کنید. این یکی از اصول معروف Go است:
Design small interfaces. Compose them when needed
قسمت قبل: نوع داده struct | گولنگ به زبان ساده
قسمت بعد: جنریک ها (Generics) | گولنگ به زبان ساده