Result Type — bu muvaffaqiyat (Success) yoki xato (Failure) bilan tugashi mumkin bo'lgan operatsiya natijasini ifodalovchi konteyner tipidir. Istisnolardan farqli o'laroq, Result xatoni oddiy qiymat sifatida uzatadi, stackni ochmasdan, bu kutilgan xatolarni boshqarishni xavfsizroq va kompozitsiyali qiladi. Apple Swift Documentation (2026) ga ko'ra, Swift da Result<Success, Failure> dastur bajarilishini to'xtatmasdan map va flatMap orqali avtomatik xato boshqaruvi bilan operatsiyalar zanjirlarini birlashtirish imkonini beradi.
Asosiy fikrlar
Result Type — bu ham muvaffaqiyatli, ham xato bilan tugashi mumkin bo'lgan operatsiya bajarilishi natijasini inkapsulatsiya qiluvchi generic tipdir. Istisnolardan farqli o'laroq, bu yerda xato normal bajarilish oqimini to'xtatadi va catch topish uchun stack ochilishini talab qiladi, Result xatoni oddiy qiymat sifatida uzatadi — chaqiruvchi tomon har doim obyektni oladi va u bilan qanday munosabatda bo'lishni o'zi hal qiladi. Bu, ayniqsa, kutilgan xatolar uchun foydalidir: noto'g'ri kiritish, biznes qoidalari, server rad etishi, bu yerda istisno juda og'ir mexanizm bo'lar edi.
Result kontseptsiyasi funksional dasturlashdan kelib chiqqan, bu yerda o'xshash turlar Either (yoki Left/Right) deb ataladi. Swift da Result Swift 5.0 da standart turga aylandi, Kotlin da Result<T> standart kutubxonada paydo bo'ldi, Dart 3.0 da — o'rnatilgan Result<T>. Har bir implementatsiya konteyner bilan ishlash uchun metodlarni taqdim etadi: map (muvaffaqiyatli qiymatni transformatsiya qilish), flatMap (Result funksiyalari zanjiri), mapError (xatoni transformatsiya qilish), fold (har ikki holni boshqarish). Result Type — mobil ishlanmada funksional xato boshqaruvining tamal toshi, kutilgan stsenariylar uchun try-catch alternativi.
Result ning asosiy afzalligi — kompozitsiyalilik. Har biri xato qaytarishi mumkin bo'lgan bir nechta operatsiyalarni ichma-ich try-catch larsiz bitta zanjirda birlashtira olasiz. Zanjirdagi har qanday operatsiya Failure bilan tugasa, butun zanjir to'xtatiladi va Failure qaytariladi — bitta if sharti yoki catch blokisiz. Bu kodni chiziqli va o'qishli qiladi, ayniqsa ko'p sonli ketma-ket API so'rovlari yoki biznes qoidalarini tekshirish stsenariylarida.
Swift da Result<Success, Failure> — ikki holatli enum: .success(Success) va .failure(Failure), bu yerda Failure Error protokoli bilan cheklangan. Swift Result — map, flatMap, mapError va get metodlari bilan to'liq funksional tip. get — alohida metod: natija muvaffaqiyatli bo'lsa Success qiymatini qaytaradi, Failure bo'lsa xato tashlaydi. Bu Result dan funksional va istisnoga asoslangan uslublar o'rtasida ko'prik sifatida foydalanish imkonini beradi: zanjirda map/flatMap orqali boshqaring, oxirida esa throws kodi bilan integratsiya uchun get ni do-catch orqali ishlating.
Swift Result generic parametrlarga ega enum, bu kompilyatorga switch yoki do-catch orqali to'liq boshqaruvni tekshirish imkonini beradi. NetworkError enum ga yangi holat qo'shsangiz, kompilyator bu holat boshqarilmagan barcha switch ifodalarida xato beradi. To'liq tekshirish (exhaustive checking) — Result ning istisnolar oldidagi asosiy afzalligi: kompilyator barcha mumkin bo'lgan xatolarni kompilyatsiya bosqichida hisobga olinishini kafolatlaydi. Buning aksincha, Swift da istisnolar kompilyator tomonidan tekshirilmaydi (faqat throws e'lon qilinadi, lekin xato turi emas).
enum NetworkError: Error {
case badURL
case requestFailed(String)
case decodingFailed
}
func fetchUser(id: Int) -> Result<User, NetworkError> {
guard let url = URL(string: "https://api.example.com/users/\(id)") else {
return .failure(.badURL)
}
let result = performRequest(url: url)
switch result {
case let .success(data):
if let user = try? JSONDecoder().decode(User.self, from: data) {
return .success(user)
}
return .failure(.decodingFailed)
case let .failure(error):
return .failure(.requestFailed(error.localizedDescription))
}
}
// Switch bilan ishlatish
let result = fetchUser(id: 42)
switch result {
case .success(let user):
showUser(user)
case .failure(.badURL):
logError("Invalid URL")
case .failure(.requestFailed(let msg)):
showAlert(msg)
case .failure(.decodingFailed):
logError("Decoding error")
}
Result<Success, Failure> xatoni tip darajasida tiplashtirish imkonini beradi: fetchUser funksiyasi Result<User, NetworkError> qaytaradi, bu yerda NetworkError — uch holatli aniq enum. Chaqiruvchi tomon har bir holatni to'liq qamrab oluvchi switch orqali boshqaradi — kompilyator barcha variantlar boshqarilganligini tekshiradi. To'liq switch — Result ning istisnolar oldidagi asosiy afzalligi: kompilyator .badURL, .requestFailed yoki .decodingFailed ni boshqarishni unutmasligingizni kafolatlaydi. Istisnolar holatida kompilyator boshqarishni talab qilmaydi va tutilmagan catch(.badURL) review da osonlikcha qoldirilishi mumkin.
Kotlin da Result<T> — standart kutubxonadan o'rnatilgan tip, muvaffaqiyat (T) yoki xatoni (Throwable) ifodalaydi. Swift dan farqli o'laroq, Kotlin da Result aniq xato turini ko'rsatishga imkon bermaydi — faqat Throwable. Bu soddalik uchun qilingan, ammo when ifodasi orqali qo'shimcha xato turi tekshirishini talab qiladi. Kotlin Result fold (har ikki holni boshqarish), getOrNull (muvaffaqiyat yoki null), getOrDefault (muvaffaqiyat yoki standart qiymat), map, recover, andThen funksiyalarini qo'llab-quvvatlaydi. Kotlin ning o'ziga xosligi: Result funksiyalar chegaralari orqali to'g'ridan-to'g'ri tarqatish uchun mo'ljallanmagan — qo'shimcha adaptatsiyasiz Android SDK yoki Kotlin Coroutines API metodlari uchun qaytariladigan tip sifatida ishlatilmaydi.
fun parseJson(input: String): Result<JsonObject> {
return runCatching {
JsonParser.parseString(input).asJsonObject()
}
}
fun validateEmail(email: String): Result<String> {
return if (email.contains("@")) {
Result.success(email.trim())
} else {
Result.failure(IllegalArgumentException("Invalid email"))
}
}
data class SignupData(val name: String, val email: String)
fun processSignup(name: String, email: String): SignupResult {
return validateEmail(email).fold(
onSuccess = { validateName(name) },
onFailure = { SignupResult.Error("Invalid email") }
)
}
runCatching — Kotlin da qulay o'rovchi, har qanday istisnoni tutadi va Result.failure qaytaradi. validateEmail tekshirishga qarab Result.success yoki Result.failure qaytaradi. fold har ikki holni ixcham boshqaradi: Success da keyingi validatsiya funksiyasi chaqiriladi, Failure da — SignupResult.Error qaytariladi. Muhim: Kotlin Result data class maydonlarida saqlash yoki to'g'ridan-to'g'ri suspend funksiyalar chegaralari orqali uzatish uchun mo'ljallanmagan — Jetpack Compose yoki MVVM da UI holatlarini ifodalash uchun o'z sealed class laringizdan (Success/Error/Loading) foydalaning.
Dart 3.0 dan boshlab standart kutubxonada o'rnatilgan Result<T> paydo bo'ldi — ikki konstruktorli sealed class: T.ok() (muvaffaqiyat) va Error.error() (Object va StackTrace bilan xato). Dart 3.0 dan oldin Flutter dasturchilari dartz paketidan Either<L, R> yoki o'z sealed class laridan foydalanardilar. Dart da o'rnatilgan Result minimal: to'g'ridan-to'g'ri map/flatMap taqdim etmaydi — bu funksiyalar when orqali yoki extension methods yordamida amalga oshirilishi kerak. Jiddiy funksional ishlov berish uchun fpdart dan Either map, flatMap, mapLeft, fold, andThen va bind operatorlari bilan kuchliroq yechim bo'lib qolmoqda.
Either<L, R> — fpdart paketidan chap-assotsiativ tip, bu yerda Left — xato, Right — muvaffaqiyat. O'rnatilgan Result<T> dan farqli o'laroq, Either xatoni tip parametri (L) darajasida tiplashtiradi, bu kompilyatsiya bosqichida xato turlarini farqlash imkonini beradi. fpdart paketi to'liq funksional kombinatorlar to'plamini taqdim etadi: map (Right -> Right), mapLeft (Left -> Left), flatMap (bind — ichma-ich Either), andThen (transformatsiyasiz zanjir), fold (Either dan chiqish), getOrElse (standart qiymat). Funksional yondashuv bilan Flutter ilovalari uchun Either de-fakto standart hisoblanadi.
import 'dart:convert';
import 'package:fpdart/fpdart.dart';
class UserService {
Either<AppError, User> fetchUser(String id) {
try {
final response = await http.get(
Uri.parse('https://api.example.com/users/$id')
);
if (response.statusCode == 200) {
final user = User.fromJson(
json.decode(response.body)
);
return Either.of(user);
}
return Either.left(
AppError.serverError(response.statusCode)
);
} on SocketException catch (e) {
return Either.left(AppError.networkError(e.message));
}
}
}
// Fold bilan ishlatish
final result = await service.fetchUser('42');
result.fold(
(left) => showError(left.message),
(right) => showUser(right),
);
Either<L, R> fpdart dan — chap-assotsiativ tip: Left — xato, Right — muvaffaqiyat. fetchUser Either<AppError, User> qaytaradi, bu yerda AppError — aniq xato turlari bilan sealed class (serverError, networkError). fold har ikki holni boshqaradi: birinchi callback Left (xato) uchun, ikkinchi callback Right (muvaffaqiyat) uchun. Dart 3.0 da o'rnatilgan Result ham fold ni qo'llab-quvvatlaydi, lekin map/flatMap ni taqdim etmaydi. fpdart dan Either zanjirlari uchun map, flatMap (bind), mapLeft, andThen — xatolar kompozitsiyasi uchun to'liq funksional kombinatorlar to'plami mavjud.
Result ning istisnolar oldidagi asosiy afzalligi — kompozitsiya. Har biri xato qaytarishi mumkin bo'lgan bir nechta operatsiyalaringiz bo'lsa, ularni map va flatMap orqali bitta zanjirda birlashtira olasiz, hech qanday ichma-ich if yoki try-catch siz. map muvaffaqiyatli qiymatni transformatsiya qiladi: Result.success(x) -> Result.success(f(x)). flatMap (shuningdek bind yoki andThen deb ataladi) — transformatsiyaning o'zi Result qaytarganda: Result.success(x) -> f(x) -> Result<Y>. Har qanday qadamda Failure yuz bersa, keyingi operatsiyalar bajarilmaydi — zanjir to'xtatiladi.
data class UserRequest(val userId: String, val token: String)
sealed class AuthError {
data object InvalidToken : AuthError()
data class UserNotFound(val id: String) : AuthError()
}
typealias Outcome<T> = Either<AuthError, T>
fun validateToken(token: String): Outcome<String> =
if (token.isNotBlank()) Either.right(token)
else Either.left(AuthError.InvalidToken)
fun fetchProfile(userId: String): Outcome<Profile> =
if (userId == "42") Either.right(Profile("Alice"))
else Either.left(AuthError.UserNotFound(userId))
// flatMap orqali kompozitsiya (fpdart da andThen)
val result = validateToken("abc123")
.flatMap { fetchProfile("42") }
.map { it.name }
.getOrElse { "Guest" }
println(result) // "Alice"
Zanjir: validateToken -> fetchProfile -> map name -> getOrElse "Guest". validateToken Left (InvalidToken) qaytarsa, zanjir to'xtatiladi va "Guest" qaytariladi. fetchProfile Left (UserNotFound) qaytarsa — ham "Guest". Har ikki operatsiya muvaffaqiyatli bo'lsa — profil nomi. flatMap har biri muvaffaqiyatsiz bo'lishi mumkin bo'lgan Either funksiyalarini bitta chiziqli zanjirda birlashtirish imkonini beradi. An'anaviy istisno uslubida xuddi shu kod ikkita ichma-ich try-catch yoki null tekshiruvlarini talab qilardi. getOrElse oxirida — kompozitsiyadan chiqish nuqtasi, Failure holati uchun standart qiymatni taqdim etadi.
Result va istisnolar — bir-birini istisno qiluvchi yondashuvlar emas. Har birining o'z qo'llanish sohasi bor va yaxshi loyihalashtirilgan mobil ilovada ikkalasi ham qo'llaniladi. Tanlov xatoning kutilgan (expected) yoki kutilmagan (unexpected) ekanligiga bog'liq. Result — biznes mantiqining bir qismi bo'lgan kutilgan xatolar uchun: noto'g'ri email, hisobda yetarli mablag' yo'qligi, so'rov limitining oshib ketishi. Istisnolar — kutilmagan tizim xatolari uchun: tarmoq uzilishi, OutOfMemoryError, NullPointerException (bo'lmasligi kerak, lekin bo'ladi).
| Mezon | Result Type | Istisnolar (Exception/Error) |
|---|---|---|
| Xato turi | Kutilgan (biznes mantig'i) | Kutilmagan (tizim) |
| Unumdorlik | Past narx (stack ochilmasdan) | Yuqori narx (stack unwinding, StackTrace olish) |
| Kompozitsiya | map/flatMap orqali — chiziqli zanjirlar | Ichma-ich try-catch — o'qish qiyin |
| Kompilyator | To'liq tekshirish (switch/when) | Faqat Java da checked exceptions |
| Bajarilish oqimi | To'xtatilmaydi — xato qiymat sifatida | Eng yaqin catch gacha to'xtatiladi |
| Testlash | Oson: natijani tekshirish, assert isSuccess/isError | assertThrows va mock obyektlarini talab qiladi |
| Qachon ishlatish | Biznes validatsiyasi, so'rov zanjirlari, formalar | Tarmoq uzilishi, I/O xatolar, tizim qulashlari |
Amaliy qoida: agar xato ilovaning normal ish oqimining bir qismi bo'lsa (foydalanuvchi noto'g'ri email kiritdi, kirish huquqlari yetarli emas) — Result dan foydalaning. Agar xato istisno holat bo'lsa (server javob bermaydi, xotira tugadi) — istisnolardan foydalaning. Mobil ishlanmada qatlamlar chegaralarida Result (UseCase -> ViewModel) va qatlamlar ichida istisnolar (API -> Repository) — ikkala yondashuvning afzalliklarini birlashtiruvchi keng tarqalgan namuna.
Mavjud istisnoga asoslangan kodni Result ga migratsiya qilish bosqichma-bosqich bo'lishi kerak. Qatlamlar chegaralaridan boshlang: throws funksiyalarining chaqiruvlarini Result { try ... } (Swift) yoki runCatching { ... } (Kotlin) bilan o'rang. Keyin Repository va UseCase metodlarining qaytariladigan tipini Result/Either bilan almashtiring, ichki implementatsiyani istisnolarda qoldirib. Oxirgi bosqichda ViewModel ni migratsiya qiling: istisnolar bilan UiState o'rniga sealed class UiState<T> (Loading, Success, Error) dan foydalaning, bu yerda Error Throwable emas, domen xatosini saqlaydi. Bosqichma-bosqich migratsiya har bir qatlamni global refaktoring qilmasdan alohida test qilish imkonini beradi.
Tez-tez so'raladigan savollar
Optional (T?) qiymatning mavjudligi yoki yo'qligini ifodalaydi — nil "ma'lumot yo'q" degani, lekin sababini aytmaydi. Result (Success/Failure) nafaqat muvaffaqiyatni, balki aniq tip bilan xato sababini ham o'z ichiga oladi. Qiymatning yo'qligi normal bo'lsa Optional dan foydalaning (masalan, profilning ixtiyoriy maydoni), xato haqida ma'lumot kerak bo'lsa — Result.
Swift da Result { try throwingFunc() } dan foydalaning — Result konstruktori throws yopilishini qabul qiladi. Kotlin da — runCatching { throwingFunc() }, Result<T> qaytaradi. Dart da — Result<T>.tryCatch(() => throwingFunc()). Bu istisnoga asoslangan kodni Result zanjirlariga oson integratsiya qilish imkonini beradi.
Muvaffaqiyatli qiymatni o'zgartirmasdan xato turini transformatsiya qilish uchun mapError (Swift) yoki mapLeft (Dart/Kotlin da Either) dan foydalaning. Har ikki holni boshqarib, yagona qiymat qaytarish kerak bo'lsa — fold dan foydalaning. Zanjirni to'xtatmasdan loglash uchun onFailure (Kotlin) yoki prefiks inspection point dan foydalaning.
Ha, lekin ehtiyot bilan. Kotlin Result<T> K2 compiler va refleksiya xususiyatlari tufayli to'g'ridan-to'g'ri suspend funksiyalarning qaytariladigan tipi sifatida tavsiya etilmaydi. Korutinlarda holatlarni ifodalash uchun o'z sealed class NetworkResult<T> (Success, Error, Loading) dan foydalaning. Biznes mantig'idagi kutilgan xatolar uchun Arrow dan Either kuchliroq alternativadir.
fold — ikki callback qabul qiluvchi metod: onSuccess (muvaffaqiyatli hol uchun) va onFailure (xato holati uchun), va istalgan turdagi yagona qiymat qaytaradi. Bu switch ifodasining ekvivalenti, lekin yuqori darajali funksiya shaklida. fold — Success/Failure ni UiState, foydalanuvchi uchun string yoki boshqa Result ga aylantiradigan Result zanjirlaridan asosiy chiqish nuqtasidir.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.