Either — نوع تابعی است که مقدار یکی از دو گزینه ممکن را نشان میدهد: چپ (Left) برای خطا و راست (Right) برای موفقیت. برخلاف استثناها، Either مدیریت خطا را در سطح نوع صریح میکند و به بلوکهای try-catch نیاز ندارد. طبق دادههای Arrow, 2026، Either به طور گسترده در پروژههای Kotlin برای ترکیب عملیاتی که ممکن است شکست بخورند، بدون عوارض جانبی استفاده میشود.
نکات اصلی
Either — یک نوع داده جبری برگرفته از برنامهنویسی تابعی است که مقدار دقیقاً یکی از دو نوع ممکن را نشان میدهد. در زمینه مدیریت خطا، قرارداد زیر پذیرفته شده است: نوع چپ (Left) حاوی شرح مشکل است و راست (Right) — نتیجه موفق.
مفهوم Either به زبان Haskell و دسته انواع Either a b برمیگردد، جایی که a نوع مقدار چپ و b نوع مقدار راست است. در توسعه موبایل، Either به لطف کتابخانه Arrow برای Kotlin و رویکردهای تابعی در Swift محبوبیت یافته است.
مزیت کلیدی Either نسبت به استثناها — عدم وجود مسیرهای اجرای پنهان است. تابعی که Either برمیگرداند به صراحت در امضای خود اعلام میکند که ممکن است با خطا پایان یابد. کامپایلر بررسی میکند که آیا هر دو گزینه پردازش شدهاند.
برخلاف پرتاب استثناها، Either شفافیت جریان داده را حفظ میکند. فراخوانی تابعی که Either برمیگرداند به try-catch در سمت کد فراخوان نیاز ندارد — pattern-matching یا fold کافی است. این امر به ویژه در معماریهایی با رویکرد واکنشی مهم است، جایی که هر منبع داده Either برمیگرداند و زنجیره تبدیل از طریق map و flatMap ساخته میشود.
Either از دو زیرنوع تشکیل شده است: Left و Right. یک نمونه Either در هر لحظه فقط میتواند یکی از آنها باشد. امضای معمول در Kotlin به صورت Either<E, A> است، جایی که E نوع خطا و A نوع مقدار موفق است.
Left حالت خرابی را نشان میدهد. برخلاف استثناها، Left جریان اجرا را قطع نمیکند — فقط مقداری را برمیگرداند که باید پردازش شود. نوع خطا میتواند هر چیزی باشد: String، Int، sealed class سفارشی یا مدل دامنه.
Right حاوی نتیجه صحیح عملیات است. نام نشاندهنده «صحت» است — طبق قرارداد Right به معنای موفقیت است. تبدیلهای map و flatMap روی Right اعمال میشوند که این امکان را میدهد زنجیرههای محاسباتی بدون بررسی هر مرحله ساخته شوند.
flatMap — مکانیزم اصلی ترکیب Either است. اگر مقدار فعلی Right باشد، flatMap تابع ارسال شده را اعمال میکند و Either جدیدی برمیگرداند. اگر Left باشد — flatMap تبدیل را رد میکند و خطا را به جلو منتقل میکند. این رفتار short-circuit evaluation نامیده میشود.
علاوه بر flatMap، Either از mapLeft برای تبدیل خطا، fold برای پردازش هر دو گزینه در یک مکان و getOrElse برای استخراج مقدار با پیشفرض پشتیبانی میکند. این توابع همه سناریوها را پوشش میدهند: از استخراج ساده تا ترکیب پیچیده با فراخوانیهای ناهمگام در کوروتینهای Kotlin یا Combine در Swift.
fun parseInt(input: String): Either<String, Int> =
input.toIntOrNull()?.let { Right(it) }
?: Left("امکان تبدیل وجود ندارد: $input")
fun divide(a: Int, b: Int): Either<String, Int> =
if (b == 0) Left("تقسیم بر صفر")
else Right(a / b)
val result = parseInt("10")
.flatMap { divide(it, 2) }
در اکوسیستم Kotlin Either در کتابخانه Arrow پیادهسازی شده است. کتابخانه استاندارد Kotlin Result را ارائه میدهد، اما Either انعطافپذیری بیشتری میدهد: نوع خطای دلخواه، ترکیب از طریق flatMap و پشتیبانی از الگوهای تابعی.
Arrow — کتابخانه تابعی برای Kotlin که Either، Option، Validated و انواع دیگر را اضافه میکند. Arrow.Either — sealed class با دو وراث: ArrowCore.Left و ArrowCore.Right. کتابخانه همچنین افزونههایی برای کار راحت فراهم میکند: .getOrElse()، .fold()، .mapLeft().
یک سناریوی واقعی را در نظر بگیریم — درخواست شبکه در برنامه Android با خطاهای احتمالی: عدم وجود شبکه، خطای سرور، پاسخ نادرست. Either به شما امکان میدهد همه گزینهها را در یک نوع بازگشتی ترکیب کنید.
sealed class NetworkError {
data class NoConnection(val message: String): NetworkError()
data class ServerError(val code: Int): NetworkError()
data class ParseError(val detail: String): NetworkError()
}
suspend fun fetchUser(id: String): Either<NetworkError, User> {
return try {
val response = api.getUser(id)
if (response.isSuccessful) {
Right(response.body()!!)
} else {
Left(NetworkError.ServerError(response.code()))
}
} catch (e: IOException) {
Left(NetworkError.NoConnection(e.message ?: ""))
}
}
در Swift از نسخه 5.0 نوع داخلی Result ظاهر شده است که از نظر مفهومی شبیه Either است اما محدودیتهایی دارد: خطا باید با پروتکل Error مطابقت داشته باشد و مقدار موفق — یک نوع. Either در Swift از طریق enum با دو پارامتر جنریک پیادهسازی میشود.
Result<Success, Failure> — نوع داخلی Swift که در آن Failure: Error. Either محدودیتی بر نوع خطا اعمال نمیکند که این امکان را میدهد String، ساختارهای سفارشی یا حتی چند نوع خطا را از طریق enumهای تودرتو ذخیره کنید.
enum Either<E, A> {
case left(E)
case right(A)
func map<B>(_ transform: (A) -> B) -> Either<E, B> {
switch self {
case .left(let e): return .left(e)
case .right(let a): return .right(transform(a))
}
}
}
let result: Either<String, Int> = .right(42)
let mapped = result.map { $0 * 2 }
Either برای سناریوهایی که نیاز به مدیریت خطای صریح و نوعامن بدون استثنا دارند بهینه است. موارد اصلی استفاده در توسعه موبایل با Kotlin و Swift را بررسی میکنیم.
از Either برای عملیات ساده بدون عوارض جانبی استفاده نکنید — مقدار بازگشتی معمولی قابل اعتمادتر و خواناتر است. Either همچنین زمانی که خرابی یک موقعیت استثنایی است نه یک سناریوی مورد انتظار، اضافی است.
Either همچنین هنگام کار با کوروتینها در Kotlin مؤثر است. تابعی که Either برمیگرداند میتواند در داخل کوروتین با مدیریت خطا از طریق fold یا mapLeft بدون مسدود کردن رشته فراخوانی شود. این امر به ویژه در برنامههای Android با معماری MVVM مفید است، جایی که هر مخزن Either برمیگرداند و ViewModel نتیجه را به UiState تبدیل میکند.
توسعهدهندگانی که برای اولین بار با Either آشنا میشوند اغلب اشتباهات مشابهی مرتکب میشوند. رایجترین آنها و راههای اجتناب را بررسی میکنیم.
سوالات متداول
Optional وجود یا عدم وجود مقدار (Some/None) را نشان میدهد اما دلیل عدم وجود را بیان نمیکند. Either دو نوع مشخص میدهد — چپ برای خطا و راست برای موفقیت، که امکان انتقال زمینه خرابی را فراهم میکند.
در Java Either داخلی وجود ندارد، اما کتابخانههای Vavr و functionaljava پیادهسازی را ارائه میدهند. در توسعه Android، Either از Vavr یک جایگزین محبوب برای سبک تابعی با لامبداها است.
Sealed class در Kotlin زمانی راحتتر است که گزینهها بیش از دو تا باشند یا ساختار متفاوتی داشته باشند. برای نتیجه باینری (خطا/موفقیت) Either فشردهتر است و ترکیبکنندههای تابعی آماده ارائه میدهد.
Either غیرقابل تغییر و به طور پیشفرض ایمن از نظر نخ است. در Kotlin با کوروتینها Either به خوبی ترکیب میشود: flatMap در داخل coroutine scope کار میکند و مدیریت خطا نیازی به قفل ندارد.
خیر. Either برای عملیات با خرابیهای مورد انتظار (شبکه، اعتبارسنجی، منطق کسبوکار) مناسب است. برای getterهای ساده و محاسبات بدون عوارض جانبی، نوع معمولی خواناتر است و پیچیدگی اضافی ایجاد نمیکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید