Result Type — başarı (Success) veya hata (Failure) ile tamamlanabilen bir işlemin sonucunu temsil eden bir kapsayıcı türdür. İstisnaların aksine, Result hatayı yığın açma olmadan normal bir değer olarak iletir ve beklenen hataların işlenmesini daha güvenli ve birleştirilebilir hale getirir. Apple Swift Documentation (2026)'ya göre, Swift'teki Result<Success, Failure>, program yürütmeyi kesintiye uğratmadan map ve flatMap aracılığıyla otomatik hata işleme ile işlemleri zincirlemenize olanak tanır.
Önemli Noktalar
Result Type, başarılı olabilen veya başarısız olabilen bir işlemin sonucunu kapsülleyen genel bir türdür. Bir hatanın normal akışı kesintiye uğrattığı ve bir catch bloğu bulmak için yığın açma gerektirdiği istisnaların aksine, Result hatayı normal bir değer olarak iletir — çağıran her zaman bir nesne alır ve onu nasıl ele alacağına karar verir. Bu, özellikle beklenen hatalar için kullanışlıdır: geçersiz giriş, iş kuralları, sunucu reddi; burada istisnalar çok ağır bir mekanizma olurdu.
Result kavramı, benzer türlerin Either (veya Left/Right) olarak adlandırıldığı işlevsel programlamadan gelir. Swift'te Result, Swift 5.0'da standart bir tür haline geldi; Kotlin'de Result<T> standart kütüphanede göründü; Dart 3.0'da yerleşik Result<T> tanıtıldı. Her uygulama, kapsayıcıyla çalışmak için yöntemler sağlar: map (başarı değerini dönüştürme), flatMap (Result işlevlerini zincirleme), mapError (hatayı dönüştürme), fold (her iki durumu da ele alma). Result Type, mobil geliştirmede işlevsel hata işlemenin temel taşıdır ve beklenen senaryolar için try-catch'e bir alternatiftir.
Result'un temel avantajı birleştirilebilirliktir. Her biri başarısız olabilen birden çok işlemi, iç içe try-catch blokları olmadan tek bir zincirde birleştirebilirsiniz. Zincirdeki herhangi bir işlem Failure ile başarısız olursa, tüm zincir kesintiye uğrar ve Failure döndürür — tek bir if koşulu veya catch bloğu olmadan. Bu, özellikle birden çok sıralı API isteği veya iş kuralı denetimi olan senaryolarda kodu doğrusal ve okunabilir hale getirir.
Swift'te, Result<Success, Failure> iki durumlu bir enum'dur: .success(Success) ve .failure(Failure), burada Failure Error protokolü tarafından kısıtlanmıştır. Swift Result, map, flatMap, mapError ve get yöntemlerine sahip tam işlevsel bir türdür. get özel bir yöntemdir: sonuç başarılıysa Success değerini döndürür ve Failure ise hatayı fırlatır. Bu, Result'un işlevsel ve istisna tabanlı stiller arasında bir köprü görevi görmesini sağlar: bir zincirde map/flatMap aracılığıyla işleme ve sonunda throws koduyla entegre olmak için do-catch ile get kullanma.
Swift Result, genel parametrelere sahip bir enum'dur ve derleyicinin switch veya do-catch aracılığıyla kapsamlı işlemeyi zorlamasına olanak tanır. NetworkError enum'una yeni bir durum eklerseniz, derleyici bu durumun işlenmediği tüm switch ifadelerinde bir hata üretir. Kapsamlı denetim, Result'un istisnalara göre ana avantajıdır: derleyici, derleme zamanında tüm olası hataların hesaba katıldığını garanti eder. Buna karşılık, Swift'te istisnalar derleyici tarafından denetlenmez (yalnızca throws bildirilir, ancak hata türü bildirilmez).
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 ile kullanım
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>, tür düzeyinde hatayı tiplemeye olanak tanır: fetchUser işlevi, NetworkError'un üç durumlu somut bir enum olduğu Result<User, NetworkError> döndürür. Çağıran, kapsamlı kapsamla switch aracılığıyla her durumu işler — derleyici tüm varyantların işlendiğini denetler. Kapsamlı switch, Result'un istisnalara göre önemli bir avantajıdır: derleyici, .badURL, .requestFailed veya .decodingFailed'i işlemeyi unutmayacağınızı garanti eder. İstisnalarda derleyici işleme gerektirmez ve kod incelemesinde eksik bir catch(.badURL) kolayca gözden kaçabilir.
Kotlin'de, Result<T> standart kütüphaneden başarıyı (T) veya hatayı (Throwable) temsil eden yerleşik bir türdür. Swift'in aksine, Kotlin Result somut bir hata türü belirtmeye izin vermez — yalnızca Throwable. Bu basitlik için yapılmıştır ancak when ifadesi aracılığıyla ek hata türü denetimi gerektirir. Kotlin Result, fold (her iki durumu işleme), getOrNull (başarı veya null), getOrDefault (başarı veya varsayılan), map, recover, andThen işlevlerini destekler. Kotlin'in bir özelliği: Result, işlev sınırları boyunca doğrudan yayılmak üzere tasarlanmamıştır — ek uyarlama olmadan Android SDK yöntemleri veya Kotlin Coroutines API için dönüş türü olarak kullanılamaz.
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'de herhangi bir istisnayı yakalayan ve Result.failure döndüren kullanışlı bir sarmalayıcıdır. validateEmail, doğrulamaya bağlı olarak Result.success veya Result.failure döndürür. fold, her iki durumu da kompakt bir şekilde işler: Success'te sonraki doğrulama işlevi çağrılır; Failure'da SignupResult.Error döndürülür. Önemli: Kotlin Result, veri sınıfı alanlarında depolama veya askı işlevi sınırları boyunca doğrudan iletim için tasarlanmamıştır — Jetpack Compose veya MVVM'de UI durumlarını temsil etmek için özel sealed class'lar (Success/Error/Loading) kullanın.
Dart 3.0'dan itibaren standart kütüphane, yerleşik bir Result<T> içerir — iki kurucuya sahip sealed bir sınıf: T.ok() (başarı) ve Error.error() (Object ve StackTrace ile hata). Dart 3.0'dan önce, Flutter geliştiricileri dartz paketinden Either<L, R> veya özel sealed sınıflar kullanıyordu. Dart'taki yerleşik Result minimalisttir: doğrudan map/flatMap sağlamaz — bu işlevler when aracılığıyla veya genişletme yöntemleri kullanılarak uygulanmalıdır. Ciddi işlevsel işleme için, fpdart'tan Either, map, flatMap, mapLeft, fold, andThen ve bind işleçleri desteğiyle daha güçlü bir çözüm olmaya devam etmektedir.
Either<L, R>, fpdart paketinden sola eğilimli bir türdür; burada Left hatadır ve Right başarıdır. Yerleşik Result<T>'nin aksine, Either, tür parametresi düzeyinde (L) hatayı tipler ve derleme zamanında hata türü ayrımına olanak tanır. fpdart paketi, eksiksiz bir işlevsel birleştirici seti sağlar: map (Right -> Right), mapLeft (Left -> Left), flatMap (bind — iç içe Either), andThen (dönüşüm olmadan zincirleme), fold (Either'dan çıkış), getOrElse (varsayılan değer). İşlevsel yaklaşıma sahip Flutter uygulamaları için Either, fiili standarttı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 ile kullanım
final result = await service.fetchUser('42');
result.fold(
(left) => showError(left.message),
(right) => showUser(right),
);
Either<L, R> (fpdart) sola eğilimli bir türdür: Left — hata, Right — başarı. fetchUser, AppError'un somut hata türlerine (serverError, networkError) sahip sealed bir sınıf olduğu Either<AppError, User> döndürür. fold her iki durumu da işler: ilk geri çağırma Left (hata) için, ikincisi Right (başarı) için. Dart 3.0'da yerleşik Result da fold'u destekler, ancak map/flatMap sağlamaz. Zincirler için fpdart'tan Either, map, flatMap (bind), mapLeft, andThen sağlar — hata kompozisyonu için eksiksiz bir işlevsel birleştirici seti.
Result'un istisnalara göre ana avantajı kompozisyondur. Her biri başarısız olabilen birden çok işleminiz varsa, bunları tek bir iç içe if veya try-catch olmadan map ve flatMap kullanarak zincirleyebilirsiniz. map başarı değerini dönüştürür: Result.success(x) -> Result.success(f(x)). flatMap (bind veya andThen olarak da adlandırılır), dönüşümün kendisinin bir Result döndürdüğü durumlar içindir: Result.success(x) -> f(x) -> Result<Y>. Herhangi bir adım Failure ile başarısız olursa, sonraki işlemler yürütülmez — zincir kesintiye uğrar.
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 ile kompozisyon (fpdart'ta andThen)
val result = validateToken("abc123")
.flatMap { fetchProfile("42") }
.map { it.name }
.getOrElse { "Guest" }
println(result) // "Alice"
Zincir: validateToken -> fetchProfile -> map name -> getOrElse “Misafir”. validateToken Left (InvalidToken) döndürürse, zincir kesintiye uğrar ve “Misafir” döndürür. fetchProfile Left (UserNotFound) döndürürse — yine “Misafir”. Her iki işlem de başarılı olursa — profil adı. flatMap, her biri başarısız olabilen Either işlevlerini tek bir doğrusal zincirde birleştirmeye olanak tanır. Geleneksel istisna stilinde, aynı kod iki iç içe try-catch veya null denetimi gerektirirdi. Sondaki getOrElse, kompozisyondan çıkış noktasıdır ve Failure durumu için varsayılan bir değer sağlar.
Result ve istisnalar birbirini dışlayan yaklaşımlar değildir. Her birinin kendi alanı vardır ve iyi tasarlanmış bir mobil uygulamada her ikisi de kullanılır. Seçim, hatanın beklenen mi yoksa beklenmeyen mi olduğuna bağlıdır. Result, iş mantığının bir parçası olan beklenen hatalar içindir: geçersiz e-posta, yetersiz bakiye, hız sınırı aşımı. İstisnalar, beklenmeyen sistem hataları içindir: ağ kaybı, OutOfMemoryError, NullPointerException (olmaması gereken ancak olan).
| Kriter | Result Type | İstisnalar (Exception/Error) |
|---|---|---|
| Hata Türü | Beklenen (iş mantığı) | Beklenmeyen (sistem) |
| Performans | Düşük maliyet (yığın açma olmadan) | Yüksek maliyet (yığın açma, StackTrace yakalama) |
| Kompozisyon | map/flatMap ile — doğrusal zincirler | İç içe try-catch — okuması zor |
| Derleyici | Kapsamlı denetim (switch/when) | Yalnızca Java'da denetlenen istisnalar |
| Yürütme Akışı | Kesintiye uğramaz — hata değer olarak | En yakın catch'e kadar kesintiye uğrar |
| Test | Kolay: sonucu kontrol et, isSuccess/isError iddia et | assertThrows ve mock nesneleri gerektirir |
| Ne Zaman Kullanılmalı | İş doğrulama, istek zincirleri, formlar | Ağ kaybı, G/Ç hataları, sistem çökmeleri |
Pratik kural: hata uygulamanın normal iş akışının bir parçasıysa (kullanıcı geçersiz e-posta girdi, yetersiz izinler) — Result kullanın. Hata istisnai bir durumsa (sunucu yanıt vermiyor, bellek tükendi) — istisnaları kullanın. Mobil geliştirmede, katman sınırlarında Result (UseCase -> ViewModel) ve katmanlar içinde istisnalar (API -> Repository), her iki yaklaşımın avantajlarını birleştiren yaygın bir kalıptır.
Mevcut istisna tabanlı kodu Result'a geçirmek kademeli olmalıdır. Katman sınırlarından başlayın: throws işlev çağrılarını Result { try ... } (Swift) veya runCatching { ... } (Kotlin) ile sarın. Ardından Repository ve UseCase yöntemlerinin dönüş türünü Result/Either ile değiştirin, iç uygulamayı istisnalarda bırakarak. Son adımda, ViewModel'i geçirin: istisnalı UiState yerine, Error'un bir Throwable değil, bir alan hatası depoladığı sealed sınıf UiState<T> (Loading, Success, Error) kullanın. Kademeli geçiş, genel bir yeniden düzenleme olmadan her katmanı ayrı ayrı test etmeye olanak tanır.
Sıkça Sorulan Sorular
Optional (T?) bir değerin varlığını veya yokluğunu temsil eder — nil “veri yok” anlamına gelir ancak nedenini açıklamaz. Result (Success/Failure) yalnızca başarıyı değil, aynı zamanda somut bir türle hata nedenini de içerir. Yokluk normal olduğunda (örneğin, isteğe bağlı bir profil alanı) Optional kullanın ve hata bilgisine ihtiyacınız olduğunda Result kullanın.
Swift'te, Result { try throwingFunc() } kullanın — Result kurucusu bir throws closure alır. Kotlin'de, Result<T> döndüren runCatching { throwingFunc() } kullanın. Dart'ta, Result<T>.tryCatch(() => throwingFunc()) kullanın. Bu, istisna tabanlı kodun Result zincirlerine kolay entegrasyonunu sağlar.
Başarı değerini değiştirmeden hata türünü dönüştürmek için mapError (Swift) veya mapLeft (Dart/Kotlin'de Either) kullanın. Her iki durumu da işlemeniz ve tek bir değer döndürmeniz gerekiyorsa, fold kullanın. Zinciri kesintiye uğratmadan günlüğe kaydetmek için onFailure (Kotlin) veya bir ön ek denetim noktası kullanın.
Evet, ancak dikkatli olun. Kotlin Result<T>, K2 derleyicisi ve yansıma özellikleri nedeniyle askı işlevleri için doğrudan dönüş türü olarak önerilmez. Coroutines'de durumları temsil etmek için kendi sealed sınıfınız NetworkResult<T> (Success, Error, Loading) kullanın. İş mantığındaki beklenen hatalar için Arrow'dan Either daha güçlü bir alternatiftir.
fold, iki geri çağırma alan bir yöntemdir: onSuccess (başarı durumu için) ve onFailure (hata durumu için) ve herhangi bir türde tek bir değer döndürür. Bir switch ifadesinin eşdeğeridir ancak yüksek dereceli bir işlev olarak. fold, Result zincirlerinden ana çıkış noktasıdır; burada Success/Failure'ı UiState, kullanıcıya yönelik bir dize veya başka bir Result'a dönüştürürsünüz.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun