Result Type — uğur (Success) və ya xəta (Failure) ilə nəticələnə bilən əməliyyatın nəticəsini təmsil edən konteyner tipidir. İstisnalardan fərqli olaraq, Result xətanı adi bir dəyər kimi ötürür, stack-in açılması olmadan, bu da gözlənilən xətaların idarə edilməsini daha təhlükəsiz və kompozisiyalı edir. Apple Swift Documentation (2026)-ya görə, Swift-də Result<Success, Failure> proqramın icrasını dayandırmadan map və flatMap vasitəsilə avtomatik xəta idarəetməsi ilə əməliyyat zəncirlərini birləşdirməyə imkan verir.
Əsas məqamlar
Result Type — həm uğurla, həm də xəta ilə nəticələnə bilən əməliyyatın icra nəticəsini inkapsulyasiya edən generic tipdir. İstisnalardan fərqli olaraq, burada xəta normal icra axınını kəsir və catch tapmaq üçün stack-in açılmasını tələb edir, Result xətanı adi bir dəyər kimi ötürür — çağıran tərəf həmişə obyekti alır və onunla necə davranacağına özü qərar verir. Bu, xüsusilə gözlənilən xətalar üçün faydalıdır: səhv giriş, biznes qaydaları, serverin imtinası, burada istisna çox ağır mexanizm olardı.
Result konsepsiyası funksional proqramlaşdırmadan qaynaqlanır, burada oxşar tiplər Either (və ya Left/Right) adlanır. Swift-də Result Swift 5.0-da standart tip oldu, Kotlin-də Result<T> standart kitabxanada peyda oldu, Dart 3.0-da — daxili Result<T>. Hər bir tətbiq konteynerlə işləmək üçün metodlar təqdim edir: map (uğurlu dəyərin transformasiyası), flatMap (Result funksiyaları zənciri), mapError (xətanın transformasiyası), fold (hər iki halın idarə edilməsi). Result Type — mobil inkişafda funksional xəta idarəetməsinin təməl daşı, gözlənilən ssenarilər üçün try-catch alternatividir.
Result-un əsas üstünlüyü kompozisiyalı olmasıdır. Hər biri xəta qaytara bilən bir neçə əməliyyatı iç-içə try-catch olmadan bir zəncirdə birləşdirə bilərsiniz. Zəncirdəki hər hansı bir əməliyyat Failure ilə nəticələnərsə, bütün zəncir dayandırılır və Failure qaytarılır — bir dənə də olsun if şərti və ya catch bloku olmadan. Bu, kodu xətti və oxunaqlı edir, xüsusilə çoxsaylı ardıcıl API sorğuları və ya biznes qaydalarının yoxlanılması ssenarilərində.
Swift-də Result<Success, Failure> — iki hallı enumdur: .success(Success) və .failure(Failure), burada Failure Error protokolu ilə məhdudlaşdırılıb. Swift Result — map, flatMap, mapError və get metodları ilə tam funksional tipdir. get — xüsusi metoddur: nəticə uğurlu olarsa Success dəyərini qaytarır, Failure olarsa xəta atır. Bu, Result-dan funksional və istisna əsaslı üslublar arasında körpü kimi istifadə etməyə imkan verir: zəncirdə map/flatMap ilə idarə et, sonda isə throws kodu ilə inteqrasiya üçün get-i do-catch vasitəsilə işlət.
Swift Result generic parametrləri olan enumdur, bu da kompilyatora switch və ya do-catch vasitəsilə hərtərəfli idarəetməni yoxlamağa imkan verir. NetworkError enum-a yeni bir hal əlavə etsəniz, kompilyator bu halın idarə olunmadığı bütün switch ifadələrində xəta verəcək. Hərtərəfli yoxlama (exhaustive checking) — Result-un istisnalar qarşısında əsas üstünlüyü: kompilyator bütün mümkün xətaların qurulma mərhələsində nəzərə alındığına zəmanət verir. Bunun əksinə olaraq, Swift-də istisnalar kompilyator tərəfindən yoxlanılmır (yalnız throws bəyan edilir, lakin xəta tipi deyil).
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 ilə istifadə
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> xətanı tip səviyyəsində tipləşdirməyə imkan verir: fetchUser funksiyası Result<User, NetworkError> qaytarır, burada NetworkError — üç hallı konkret enumdur. Çağıran tərəf hər bir halı hərtərəfli əhatə edən switch vasitəsilə idarə edir — kompilyator bütün variantların işləndiyini yoxlayır. Hərtərəfli switch — Result-un istisnalar qarşısında əsas üstünlüyü: kompilyator .badURL, .requestFailed və ya .decodingFailed idarə etməyi unutmayacağınıza zəmanət verir. İstisnalar vəziyyətində kompilyator idarəetmə tələb etmir və tutulmamış catch(.badURL) review-də asanlıqla qaçırıla bilər.
Kotlin-də Result<T> — standart kitabxanadan daxili tipdir, uğur (T) və ya xətanı (Throwable) təmsil edir. Swift-dən fərqli olaraq, Kotlin-də Result konkret xəta tipini göstərməyə imkan vermir — yalnız Throwable. Bu, sadəlik üçün edilib, lakin when ifadəsi vasitəsilə əlavə xəta tipi yoxlaması tələb edir. Kotlin Result fold (hər iki halın idarə edilməsi), getOrNull (uğur və ya null), getOrDefault (uğur və ya standart dəyər), map, recover, andThen funksiyalarını dəstəkləyir. Kotlin-in xüsusiyyəti: Result funksiyaların sərhədləri arasında birbaşa yayılmaq üçün nəzərdə tutulmayıb — əlavə adaptasiya olmadan Android SDK və ya Kotlin Coroutines API metodları üçün qaytarılan tip kimi istifadə edilə bilməz.
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-də rahat sarğıcıdır, istənilən istisnanı tutur və Result.failure qaytarır. validateEmail yoxlamadan asılı olaraq Result.success və ya Result.failure qaytarır. fold hər iki halı yığcam şəkildə idarə edir: Success-də növbəti validasiya funksiyası çağırılır, Failure-də — SignupResult.Error qaytarılır. Vacib: Kotlin Result data class sahələrində saxlamaq və ya birbaşa suspend-funksiyaların sərhədləri arasında ötürmək üçün nəzərdə tutulmayıb — Jetpack Compose və ya MVVM-də UI hallarını təmsil etmək üçün öz sealed class-larınızdan (Success/Error/Loading) istifadə edin.
Dart 3.0-dan etibarən standart kitabxanada daxili Result<T> meydana çıxdı — iki konstruktoru olan sealed class: T.ok() (uğur) və Error.error() (Object və StackTrace ilə xəta). Dart 3.0-dan əvvəl Flutter tərtibatçıları dartz paketindən Either<L, R> və ya öz sealed class-larından istifadə edirdilər. Dart-da daxili Result minimaldır: birbaşa map/flatMap təqdim etmir — bu funksiyalar when vasitəsilə və ya extension methods istifadə edərək tətbiq edilməlidir. Ciddi funksional emal üçün fpdart-dan Either map, flatMap, mapLeft, fold, andThen və bind operatorları ilə daha güclü həll olaraq qalır.
Either<L, R> — fpdart paketindən sol-assosiativ tipdir, burada Left — xəta, Right — uğur. Daxili Result<T>-dən fərqli olaraq, Either xətanı tip parametri (L) səviyyəsində tipləşdirir ki, bu da kompilyasiya mərhələsində xəta tiplərini fərqləndirməyə imkan verir. fpdart paketi tam funksional kombinatorlar dəstini təqdim edir: map (Right -> Right), mapLeft (Left -> Left), flatMap (bind — iç-içə Either), andThen (transformasiyasız zəncir), fold (Either-dən çıxış), getOrElse (standart dəyər). Funksional yanaşma ilə Flutter tətbiqləri üçün Either de-fakto standartdır.
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 ilə istifadə
final result = await service.fetchUser('42');
result.fold(
(left) => showError(left.message),
(right) => showUser(right),
);
Either<L, R> fpdart-dan — sol-assosiativ tip: Left — xəta, Right — uğur. fetchUser Either<AppError, User> qaytarır, burada AppError — konkret xəta tipləri ilə sealed class (serverError, networkError). fold hər iki halı idarə edir: birinci callback Left (xəta) üçün, ikinci callback Right (uğur) üçün. Dart 3.0-da daxili Result da fold-u dəstəkləyir, lakin map/flatMap təqdim etmir. fpdart-dan Either zəncirləri üçün map, flatMap (bind), mapLeft, andThen — xətaların kompozisiyası üçün tam funksional kombinatorlar dəsti mövcuddur.
Result-un istisnalar qarşısında əsas üstünlüyü kompozisiyadır. Hər biri xəta qaytara bilən bir neçə əməliyyatınız varsa, onları map və flatMap vasitəsilə bir zəncirdə birləşdirə bilərsiniz, heç bir iç-içə if və ya try-catch olmadan. map uğurlu dəyəri transformasiya edir: Result.success(x) -> Result.success(f(x)). flatMap (həmçinin bind və ya andThen adlanır) — transformasiyanın özü Result qaytardıqda: Result.success(x) -> f(x) -> Result<Y>. Hər hansı bir addımda Failure baş verərsə, sonrakı əməliyyatlar yerinə yetirilmir — zəncir dayandırılır.
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 vasitəsilə kompozisiya (fpdart-da andThen)
val result = validateToken("abc123")
.flatMap { fetchProfile("42") }
.map { it.name }
.getOrElse { "Guest" }
println(result) // "Alice"
Zəncir: validateToken -> fetchProfile -> map name -> getOrElse “Guest”. validateToken Left (InvalidToken) qaytararsa, zəncir dayandırılır və “Guest” qaytarılır. fetchProfile Left (UserNotFound) qaytararsa — yenə “Guest”. Hər iki əməliyyat uğurlu olarsa — profil adı. flatMap hər biri uğursuz ola bilən Either funksiyalarını bir xətti zəncirdə birləşdirməyə imkan verir. Ənənəvi istisna üslubunda eyni kod iki iç-içə try-catch və ya null yoxlamaları tələb edərdi. getOrElse sonda — kompozisiyadan çıxış nöqtəsidir, Failure halı üçün standart dəyər təqdim edir.
Result və istisnalar — bir-birini istisna edən yanaşmalar deyil. Hər birinin öz tətbiq sahəsi var və yaxşı dizayn edilmiş mobil tətbiqdə hər ikisi istifadə olunur. Seçim xətanın gözlənilən (expected) və ya gözlənilməz (unexpected) olmasından asılıdır. Result — biznes məntiqinin bir hissəsi olan gözlənilən xətalar üçün: səhv email, hesabda kifayət qədər vəsait olmaması, sorğu limitinin aşılması. İstisnalar — gözlənilməz sistem xətaları üçün: şəbəkə itkisi, OutOfMemoryError, NullPointerException (olmamalıdır, amma olur).
| Meyar | Result Type | İstisnalar (Exception/Error) |
|---|---|---|
| Xəta növü | Gözlənilən (biznes məntiqi) | Gözlənilməz (sistem) |
| Performans | Aşağı xərc (stack açılmadan) | Yüksək xərc (stack unwinding, StackTrace tutulması) |
| Kompozisiya | map/flatMap vasitəsilə — xətti zəncirlər | İç-içə try-catch — oxumaq çətindir |
| Kompilyator | Hərtərəfli yoxlama (switch/when) | Yalnız Java-da checked exceptions |
| İcra axını | Kəsilmir — xəta dəyər kimi | Ən yaxın catch-ə qədər kəsilir |
| Test etmə | Asan: nəticənin yoxlanması, assert isSuccess/isError | assertThrows və mock obyektləri tələb edir |
| Nə vaxt istifadə etməli | Biznes validasiyası, sorğu zəncirləri, formalar | Şəbəkə itkisi, I/O xətaları, sistem çökmələri |
Praktik qayda: əgər xəta tətbiqin normal iş axınının bir hissəsidirsə (istifadəçi səhv email daxil edib, giriş hüquqları kifayət deyil) — Result istifadə edin. Əgər xəta müstəsna haldırsa (server cavab vermir, yaddaş qurtarıb) — istisnalardan istifadə edin. Mobil inkişafda təbəqələrin sərhədlərində Result (UseCase -> ViewModel) və təbəqələr daxilində istisnalar (API -> Repository) — hər iki yanaşmanın üstünlüklərini birləşdirən geniş yayılmış nümunədir.
Mövcud istisna əsaslı kodun Result-a miqrasiyası tədricən olmalıdır. Təbəqələrin sərhədlərindən başlayın: throws funksiyalarının çağırışlarını Result { try ... } (Swift) və ya runCatching { ... } (Kotlin) ilə sarın. Sonra Repository və UseCase metodlarının qaytarılan tipini Result/Either ilə əvəz edin, daxili tətbiqi istisnalarda saxlayaraq. Son mərhələdə ViewModel-i miqrasiya edin: istisnalarla UiState əvəzinə sealed class UiState<T> (Loading, Success, Error) istifadə edin, burada Error Throwable deyil, domen xətasını saxlayır. Tədricən miqrasiya hər təbəqəni qlobal refaktorinq olmadan ayrıca test etməyə imkan verir.
Tez-tez verilən suallar
Optional (T?) dəyərin mövcudluğunu və ya olmamasını təmsil edir — nil “məlumat yoxdur” deməkdir, lakin səbəbini demir. Result (Success/Failure) təkcə uğuru deyil, həm də konkret tiplə xətanın səbəbini ehtiva edir. Dəyərin olmaması normadırsa Optional-dan istifadə edin (məsələn, profilin opsional sahəsi), xəta haqqında məlumat lazımdırsa — Result.
Swift-də Result { try throwingFunc() } istifadə edin — Result konstruktoru throws bağlanması qəbul edir. Kotlin-də — runCatching { throwingFunc() }, Result<T> qaytarır. Dart-da — Result<T>.tryCatch(() => throwingFunc()). Bu, istisna əsaslı kodu Result zəncirlərinə asanlıqla inteqrasiya etməyə imkan verir.
Uğurlu dəyəri dəyişmədən xəta tipini transformasiya etmək üçün mapError (Swift) və ya mapLeft (Dart/Kotlin-də Either) istifadə edin. Hər iki halı idarə edib vahid dəyər qaytarmaq lazımdırsa — fold istifadə edin. Zənciri kəsmədən loglama üçün onFailure (Kotlin) və ya prefiks inspection point istifadə edin.
Bəli, amma ehtiyatla. Kotlin Result<T> K2 compiler və refleksiya xüsusiyyətlərinə görə birbaşa suspend-funksiyaların qaytarılan tipi kimi tövsiyə edilmir. Korutinlərdə halları təmsil etmək üçün öz sealed class NetworkResult<T> (Success, Error, Loading) istifadə edin. Biznes məntiqində gözlənilən xətalar üçün Arrow-dan Either daha güclü alternativdir.
fold — iki callback qəbul edən metoddur: onSuccess (uğurlu hal üçün) və onFailure (xəta halı üçün), və istənilən tipdə vahid dəyər qaytarır. Bu, switch ifadəsinin ekvivalentidir, lakin ali dərəcəli funksiya şəklində. fold — Success/Failure-ı UiState, istifadəçi üçün string və ya başqa Result-a çevirdiyiniz Result zəncirlərindən əsas çıxış nöqtəsidir.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun