reified — کلمه کلیدی در زبان Kotlin است که امکان دسترسی به نوع پارامتر generic را درون inline-function در زمان اجرا فراهم میکند. در generics معمولی type erasure اعمال میشود — اطلاعات مربوط به نوع در مرحله کامپایل پاک میشود، اما reified آن را حفظ میکند. به گفته Kotlin Documentation, 2025، reified فقط درون inline-function کار میکند، زیرا کامپایلر نوع واقعی را جایگزین میکند در مرحله inlining.
نکات اصلی
reified — اصلاحکننده پارامتر generic تابع inline است که نوع را در runtime واقعی میکند (reify به معنای «واقعی ساختن»). بدون reified نوع T درون تابع generic قابل دسترسی نیست — کامپایلر type erasure اعمال میکند و تمام اطلاعات مربوط به نوع را پاک میکند. reified کامپایلر را مجبور میکند نوع مشخصی را در محل فراخوانی جایگزین کند و آن را از طریق T::class و عملگر is قابل دسترسی سازد.
به گفته Kotlin Survey by Kodee (2024)، reified type parameters در بین ده ویژگی پرتقاضای Kotlin قرار دارند — 52٪ از توسعهدهندگان شرکتکننده در نظرسنجی از آنها استفاده میکنند، عمدتاً برای نوشتن工厂های generic، ظروف DI و سریالایزرها. reified به ویژه در ترکیب با Gson، Moshi و Kotlinx Serialization محبوب است.
از نظر فنی مکانیزم ساده است: هنگام فراخوانی تابع inline با پارامتر reified، کامپایلر نوع مشخص آرگومان (Int، String، User) را میداند و آن را به جای T قرار میدهد. در بایتکد، پارامتر reified به Class
از reified برای نوشتن توابع generic که در runtime نیاز به نوع دارند استفاده کنید — ایجاد نمونه، بررسی نوع، دریافت Class
Type erasure — مکانیزم Java و Kotlin که در آن اطلاعات مربوط به پارامترهای generic در زمان کامپایل پاک میشود. در بایتکد، List
// ❌ خطا: امکان بررسی نمونه از نوع پاک شده وجود ندارد
fun <T> checkType(value: Any) {
if (value is T) { // type erasure — T ناشناخته است
println("نوع مطابقت دارد")
}
}
// ✅ Solution: pass Class as parameter
fun <T> checkTypeWithClass(
value: Any,
clazz: Class<T>
) {
if (clazz.isInstance(value)) {
println("نوع مطابقت دارد")
}
}
در مثال، checkType به دلیل type erasure کامپایل نمیشود — کامپایلر نمیداند چه نوعی را به جای T قرار دهد. در checkTypeWithClass مشکل با ارسال صریح Class
اصلاحکننده reified قبل از پارامتر generic در تابع inline قرار میگیرد. تابع باید حتماً inline باشد — کامپایلر باید امکان جایگزینی نوع مشخص را در مرحله inlining داشته باشد.
inline fun <reified T> isA(value: Any): Boolean {
return value is T
}
fun main() {
println(isA<String>("سلام")) // true
println(isA<Int>("سلام")) // false
}
در زمان کامپایل، فراخوانی isA
اگر بایتکد isA
رایجترین کاربرد reified — بررسی نوع از طریق عملگر is. در تابع generic معمولی value is T کامپایل نمیشود. با reified این کار مانند یک کلاس معمولی کار میکند: value is String، value is List
inline fun <reified T> List<Any>.filterByType(): List<T> {
return this.filter { it is T }.map { it as T }
}
val mixed = listOf("a", 1, "b", 2)
val strings = mixed.filterByType<String>() // ["a", "b"]
val ints = mixed.filterByType<Int>() // [1, 2]
تابع گسترشی filterByType لیست را فیلتر میکند و فقط عناصر نوع مشخص شده را باقی میگذارد. بدون reified باید filterByType
بر اساس دادههای Kotlin Coroutines Guide (JetBrains, 2025)، بررسیهای نوع reified در launch و async برای ارسال نوع نتیجه coroutine استفاده میشود که از مشخص کردن صریح نوع در اکثر موارد جلوگیری میکند.
reified به T::class دسترسی میدهد — مرجعی به KClass که از آن میتوان از طریق .java Class Java را دریافت کرد. این امکان ایجاد نمونه از طریق بازتاب، کار با سریالایزرها و دریافت annotationهای کلاس را در زمان اجرا فراهم میکند.
inline fun <reified T> createInstance(): T =
T::class.java.getDeclaredConstructor().newInstance()
// استفاده
data class User(val name: String = "default")
val user = createInstance<User>()
// سریالایز کردن با Gson
inline fun <reified T> Gson.fromJson(json: String): T =
this.fromJson(json, T::class.java)
// دریافت annotationها
inline fun <reified T> hasAnnotation<A>(): Boolean where A : Annotation =
T::class.java.isAnnotationPresent(A::class.java)
Wrapper fromJson برای Gson — مثال کلاسیک استفاده از reified در production. به جای gson.fromJson(json, User::class.java) میتوان gson.fromJson
reified محدودیتهایی دارد. اول — فقط درون توابع inline کار میکند. اگر تابع را نمیتوان inline کرد (مثلاً بازگشتی است یا بیش از حد بزرگ)، reified در دسترس نیست. دوم — reified را نمیتوان مستقیماً با توابع suspend استفاده کرد، فقط از طریق wrapperهای inline.
سوم — reified با انواع پارامتری شده به طور کامل کار نمیکند. مثلاً filterByType>() ممکن است نتیجه غیرمنتظرهای بدهد، زیرا برای انواع پارامتری شده reified فقط نوع خام (List) را حفظ میکند، بدون تعیین آرگومانهای generic. برای بررسی کامل انواع پارامتری شده، بازتاب با TypeToken مورد نیاز است.
| عملیات | با reified | بدون reified |
|---|---|---|
| value is T | ✅ کار میکند | ❌ خطای کامپایل |
| T::class | ✅ کار میکند | ❌ خطای کامپایل |
| List | ⚠️ فقط raw type | ❌ خطا |
| ایجاد نمونه | ✅ از طریق بازتاب | ❌ نیاز به Class |
| تابع Suspend | ❌ فقط از طریق wrapper inline | ❌ قابل اجرا نیست |
برای مواردی که reified در دسترس نیست، از الگو با ارسال صریح Class
سؤالات متداول
کامپایلر پارامتر reified T را با نوع مشخص در زمان inlining بدنه تابع جایگزین میکند. اگر تابع inline نباشد، کامپایلر جایی برای جایگزینی نوع ندارد — فراخوانی تابع generic از طریق بایتکد واحدی انجام میشود که در آن T پاک شده است. Inline یک کپی جداگانه از بایتکد برای هر نوع-آرگومان ایجاد میکند.
خیر، reified فقط برای پارامترهای توابع قابل اعمال است. برای propertyها از الگوی inline fun
reified از انواع nullable پشتیبانی میکند: reified T : Any (non-null) و صرفاً reified T (میتواند nullable باشد). برای انواع nullable، T::class کلاس نسخه non-null را برمیگرداند (String::class برای String?). بررسی value is T null را در نظر میگیرد: اگر T = String?، آنگاه null is T = true.
حداقل. reified از بازتاب استفاده نمیکند — کامپایلر نوع مشخص را در مرحله inlining جایگزین میکند. در بایتکد این یک مرجع مستقیم به کلاس است (ldc + checkcast/invokevirtual). در مقایسه با ارسال دستی Class
بله، reified به طور فعال در Android استفاده میشود. Bundle.getParcelable
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید