17 روز پیش
توی این قسمت با جنریک ها و نحوه استفاده از آنها آشنا میشیم.
پشتیبانی از Generics در نسخه ۱.۱۸ به گولنگ اضافه شد. Generics یا نوعهای پارامتریک (Parametric Polymorphism) یکی از ویژگیهایی است که امکان نوشتن توابع، ساختارهایی را فراهم میکند که میتوانند با انواع مختلف داده کار کنند بدون اینکه مجبور باشیم برای هر نوع داده، کد جداگانهای بنویسیم.
تا قبل از معرفی جنریک ها, اگر نیاز داشتیم تابعی داشته باشیم که با نوع های مختلفی از داده ها کار کند باید به ازای هر نوع داده ای که نیاز داریم کدهای اون تابع رو چندین بار تکرار میکردیم.
برای مثال فرض کنید میخواهید تابعی داشته باشید که دو عدد را به عنوان پارامتر ورودی میگیرد و از بین این دو عدد بزرگترین مقدار را برمیگرداند. این تابع رو میتونیم به صورت زیر برای نوع های int
و float64
داشته باشیم:
در مثال بالا به دلیل اینکه هرکدام از تابع های ما نمیتوانند هر دو نوع float64
و int
رو عنوان پارامتر ورودی یا خروجی بپذیرند, مجبور شدیم دوبار یک کد کاملا یکسان رو تکرار کنیم.
برای اینکه کدهای بالا رو تکرار نکنیم راه حل های دیگه ای هم وجود داره:
هرکدوم از روش های بالا مشکلاتی دارند و راه حل تمیزی نیستن. برای مثلا اگه از type assertion / interface assertion استفاده کنیم کد ما به صورت زیر خواهد بود:
کد بالا به درستی کار میکند اما مشکلاتی دارد:
استفاده از any
باعث میشود که خوانایی برنامه پایین بیاید: در هنگام استفاده از تابع max
باید ابتدا پیاده سازی آن را چک کنیم تا متوجه شویم چه دیتا تایپ هایی را پشتیبانی میکند.
دشوار شدن نگهداری و توسعه ی کد: در هنگام کامپایل نمیتوان خطاهای احتمالی را کشف کرد. در صورتی که اشتباها تابع max
را با نوعی از داده کال کنیم که آن را پیاده سازی نمیکند با panic
در زمان اجرای برنامه (runtime) مواجهه خواهیم شد.
int
و float64
تکرار شده است.جنریک در Go به کمک type parameters
تعریف میشود. یعنی میتوان برای تابع، نوعی کلی تعریف کرد و بعداً هنگام استفاده، نوع واقعی را مشخص کرد.
با استفاده از Generics میتوانیم تابع max
را به صورت زیر بازنویسی کنیم:
در مثال بالا [int |float]
لیستِ نوعِ آرگومان ها است, همچنین int
و float
هرکدام یک نوعِ آرگومان محسوب می شوند. بنابراین نوعِ T
میتواند هرکدام از نوع های float
یا int
باشد. تابع max
یک نوعِ پارامتریک یا جنریک محسوب می شود.
در هنگام استفاده از تابع max
میتوانیم نوعِ پارامترهای ورودی و خروجی را با مشخص کردن نوع T
کنترل کنیم. در مثال زیر نوع پارامتر T
را int
در نظر گرفتیم بنابراین هردو پارامتر ورودی تابع باید از نوع int
باشند, در غیر اینصورت خطای زمان کامپایل رخ میدهد.
با استفاده از پارامتر لیست میتوان تایپ های جنریک ایجاد کرد. فرض کنید میخواهیم یک slice جنریک به نام List[T]
داشته باشم, میتوانیم آن را به صورت زیر پیاده سازی کنیم:
اگر نوع داده ی ما جنریک باشد (مثل List[T]
) میتوان متدهایی نوشت که از پارامتر تایپ های آن استفاده میکنند.
بر خلافِ تابع ها, متدها نمیتوانند دارای لیست پارامتر تایپ باشند اما میتوانند از پارامتر تایپِ نوعِ داده ی خود استفاده کنند, به عنوان مثال کد زیر با خطای زمان کامپایل مواجه میشود:
قسمت قبل: اینترفیس (interface) | گولنگ به زبان ساده
قسمت بعد: به زودی…