Result Type: mi ez, Result konténer típus és hogyan működik mobilfejlesztésben

Szerző: IT Sectr Megjelenés: 2026-05-26 Olvasási idő: 9 perc

Result Type — egy konténer típus, amely egy olyan művelet eredményét reprezentálja, amely sikerrel (Success) vagy hibával (Failure) végződhet. A kivételekkel ellentétben a Result a hibát mint közönséges értéket adja át a verem kibontása nélkül, ami a várható hibák kezelését biztonságosabbá és kompozícióra alkalmasabbá teszi. A Apple Swift Documentation (2026) szerint a Result<Success, Failure> Swift-ben lehetővé teszi műveleti láncok összekapcsolását automatikus hibakezeléssel map és flatMap segítségével, anélkül hogy megszakítaná a program végrehajtását.

Főbb pontok

  • Result Type — generikus konténer két állapottal: Success (adat) és Failure (hiba), verem kibontása nélkül
  • Swift-ben Result<Success, Failure> — beépített típus map, flatMap, mapError és get metódusokkal
  • Kotlin-ban Result<T> sikert vagy Throwable-t reprezentál, getOrNull, getOrDefault, fold függvényekkel
  • Dart-ban standard Result<T> elérhető Dart 3.0-tól, valamint Either a fpdart csomagból
  • Kompozíció map és flatMap segítségével lehetővé teszi több Result-t visszaadó művelet összekapcsolását beágyazott ellenőrzések nélkül

Mi az a Result Type?

Result Type egy generikus típus, amely egy művelet végrehajtásának eredményét kapszulázza, amely mind sikerrel, mind hibával végződhet. A kivételekkel ellentétben, ahol a hiba megszakítja a normál végrehajtási folyamatot és a verem kibontását igényli a catch megtalálásához, a Result a hibát mint közönséges értéket adja át — a hívó fél mindig kap egy objektumot, és maga dönti el, hogyan kezelje. Ez különösen hasznos a várható hibákhoz: érvénytelen bemenet, üzleti szabályok, szerver elutasítása, ahol a kivétel túl nehézkes mechanizmus lenne.

A Result koncepciója a funkcionális programozásból ered, ahol hasonló típusokat Either-nek (vagy Left/Right-nak) neveznek. Swift-ben a Result Swift 5.0-ban vált standard típussá, Kotlin-ban a Result<T> a standard könyvtárban jelent meg, Dart 3.0-ban — beépített Result<T>. Minden implementáció metódusokat biztosít a konténerrel való munkához: map (a sikeres érték transzformációja), flatMap (Result függvények lánca), mapError (a hiba transzformációja), fold (mindkét eset kezelése). Result Type — a funkcionális hibakezelés sarokköve a mobilfejlesztésben, a try-catch alternatívája várható forgatókönyvekhez.

A Result legfontosabb előnye a kompozícióképesség. Több műveletet, amelyek mindegyike visszaadhat hibát, egyetlen láncba kapcsolhatsz beágyazott try-catch nélkül. Ha bármelyik művelet a láncban Failure-rel végződik, az egész lánc megszakad és Failure-t ad vissza — egyetlen if feltétel vagy catch blokk nélkül. Ez lineárissá és olvashatóvá teszi a kódot, különösen több egymást követő API-kérés vagy üzleti szabályok ellenőrzésének forgatókönyveiben.

Result Swift-ben

Swift-ben a Result<Success, Failure> egy enum két esettel: .success(Success) és .failure(Failure), ahol a Failure az Error protokollal van korlátozva. A Swift Result egy teljes funkcionális típus a map, flatMap, mapError és get metódusokkal. A get egy különleges metódus: visszaadja a Success értéket, ha az eredmény sikeres, és hibát dob, ha Failure. Ez lehetővé teszi a Result használatát hídként a funkcionális és a kivétel-alapú stílusok között: kezeld map/flatMap segítségével a láncban, a végén pedig — get segítségével do-catch-en keresztül a throws kóddal való integrációhoz.

Result enum és kimerítő switch

A Swift Result egy enum generikus paraméterekkel, ami lehetővé teszi a fordítónak, hogy ellenőrizze a kimerítő kezelést switch vagy do-catch segítségével. Ha új esetet adsz a NetworkError enum-hoz, a fordító hibát ad minden olyan switch kifejezésben, ahol ez az eset nincs kezelve. Kimerítő ellenőrzés (exhaustive checking) — a Result fő előnye a kivételekkel szemben: a fordító garantálja, hogy az összes lehetséges hiba figyelembe van véve a fordítási szakaszban. Ezzel szemben a kivételeket a fordító nem ellenőrzi Swift-ben (csak a throws van deklarálva, de a hiba típusa nem).

swift
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))
    }
}

// Használat switch-csel
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> lehetővé teszi a hiba típus szintű tipizálását: a fetchUser függvény Result<User, NetworkError>-t ad vissza, ahol a NetworkError egy konkrét enum három esettel. A hívó fél minden esetet switch segítségével kezel kimerítő lefedettséggel — a fordító ellenőrzi, hogy minden variáns kezelve van. Kimerítő switch — a Result kulcsfontosságú előnye a kivételekkel szemben: a fordító garantálja, hogy nem felejted el kezelni a .badURL, .requestFailed vagy .decodingFailed eseteket. A kivételek esetében a fordító nem igényel kezelést, és egy el nem kapott catch(.badURL) könnyen észrevétlen marad a review-ban.

Result Kotlin-ban

Kotlin-ban a Result<T> egy beépített típus a standard könyvtárból, amely sikert (T) vagy hibát (Throwable) reprezentál. A Swift-tel ellentétben Kotlin-ban a Result nem teszi lehetővé egy konkrét hiba típus megadását — csak Throwable. Ez az egyszerűség kedvéért történt, de a hiba típusának további ellenőrzését igényli a when kifejezés segítségével. A Kotlin Result támogatja a fold (mindkét eset kezelése), getOrNull (siker vagy null), getOrDefault (siker vagy alapértelmezett érték), map, recover, andThen függvényeket. A Kotlin sajátossága: a Result nem közvetlen propagálásra szolgál a függvényhatárokon keresztül — nem használható visszatérési típusként az Android SDK vagy Kotlin Coroutines API metódusaihoz további adaptáció nélkül.

kotlin
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 — egy kényelmes wrapper Kotlin-ban, amely elkap minden kivételt és Result.failure-t ad vissza. validateEmail Result.success vagy Result.failure értéket ad vissza az ellenőrzéstől függően. fold mindkét esetet tömören kezeli: Success esetén a következő validációs függvény hívódik meg, Failure esetén — SignupResult.Error kerül visszaadásra. Fontos: a Kotlin Result nem alkalmas data class mezőkben való tárolásra vagy közvetlen átadásra suspend függvények határain keresztül — használd a saját sealed class-odat (Success/Error/Loading) az UI állapotok reprezentálásához Jetpack Compose-ban vagy MVVM-ben.

Result Dart-ban és Flutter-ben

Dart 3.0-tól a standard könyvtárban megjelent a beépített Result<T> — egy sealed class két konstruktorral: T.ok() (siker) és Error.error() (hiba Object és StackTrace paraméterekkel). Dart 3.0 előtt a Flutter fejlesztők Either<L, R>-t használtak a dartz csomagból vagy saját sealed class-okat. A beépített Result Dart-ban minimalista: nem biztosítja közvetlenül a map/flatMap függvényeket — ezeket when segítségével vagy extension methods használatával kell implementálni. Komoly funkcionális kezeléshez a fpdart-ból származó Either marad az erősebb megoldás, támogatva a map, flatMap, mapLeft, fold, andThen és bind operátorokat.

Either a fpdart-ból

Either<L, R> — egy bal-asszociált típus a fpdart csomagból, ahol a Left — hiba, a Right — siker. A beépített Result<T>-vel ellentétben az Either a hibát a típusparaméter (L) szintjén tipizálja, ami lehetővé teszi a hiba típusok megkülönböztetését a fordítási szakaszban. A fpdart csomag teljes funkcionális kombinator készletet biztosít: map (Right -> Right), mapLeft (Left -> Left), flatMap (bind — beágyazott Either), andThen (lánc transzformáció nélkül), fold (kilépés Either-ből), getOrElse (alapértelmezett érték). Funkcionális megközelítésű Flutter alkalmazásokhoz az Either a de facto szabvány.

dart
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));
        }
    }
}

// Használat fold-dal
final result = await service.fetchUser('42');
result.fold(
    (left)  => showError(left.message),
    (right) => showUser(right),
);

Either<L, R> a fpdart-ból — bal-asszociált típus: Left — hiba, Right — siker. fetchUser Either<AppError, User>-t ad vissza, ahol az AppError — sealed class konkrét hiba típusokkal (serverError, networkError). fold mindkét esetet kezeli: az első callback a Left (hiba), a második a Right (siker) számára. Dart 3.0-ban a beépített Result is támogatja a fold-ot, de nem biztosít map/flatMap-et. A láncokhoz a fpdart-ból származó Either map, flatMap (bind), mapLeft, andThen függvényeket biztosít — teljes funkcionális kombinator készletet a hibák kompozíciójához.

Result kompozíció map és flatMap segítségével

A Result fő előnye a kivételekkel szemben a kompozíció. Ha több műveleted van, amelyek mindegyike visszaadhat hibát, összekapcsolhatod őket egy láncba map és flatMap segítségével egyetlen beágyazott if vagy try-catch nélkül. map transzformálja a sikeres értéket: Result.success(x) -> Result.success(f(x)). flatMap (más néven bind vagy andThen) — azokra az esetekre, amikor a transzformáció maga is Result-ot ad vissza: Result.success(x) -> f(x) -> Result<Y>. Ha bármelyik lépésben Failure történik, a következő műveletek nem hajtódnak végre — a lánc megszakad.

kotlin
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))

// Kompozíció flatMap segítségével (andThen a fpdart-ban)
val result = validateToken("abc123")
    .flatMap { fetchProfile("42") }
    .map { it.name }
    .getOrElse { "Guest" }

println(result) // "Alice"

Lánc: validateToken -> fetchProfile -> map name -> getOrElse „Vendég“. Ha a validateToken Left (InvalidToken) értéket ad vissza, a lánc megszakad és „Vendég“ kerül visszaadásra. Ha a fetchProfile Left (UserNotFound) értéket ad vissza — szintén „Vendég“. Ha mindkét művelet sikeres — a profil neve. flatMap lehetővé teszi az Either függvények összekapcsolását, amelyek mindegyike meghiúsulhat, egyetlen lineáris láncba. A hagyományos kivétel-stílusban ugyanez a kód két beágyazott try-catch-t vagy null ellenőrzést igényelne. getOrElse a végén — a kompozícióból való kilépési pont, amely alapértelmezett értéket biztosít a Failure esetre.

Result vs Kivételek: mikor mit válassz

A Result és a kivételek — nem egymást kizáró megközelítések. Mindegyiknek megvan a maga alkalmazási területe, és egy jól tervezett mobil alkalmazásban mindkettőt használják. A választás attól függ, hogy a hiba várható (expected) vagy váratlan (unexpected). Result — a várható hibákhoz, amelyek az üzleti logika részét képezik: érvénytelen e-mail, elégtelen egyenleg a számlán, kérési limit túllépése. Kivételek — a váratlan rendszerhibákhoz: hálózati kapcsolat megszakadása, OutOfMemoryError, NullPointerException (amelyeknek nem kellene előfordulniuk, de előfordulnak).

SzempontResult TypeKivételek (Exception/Error)
Hiba típusaVárható (üzleti logika)Váratlan (rendszer)
TeljesítményAlacsony költség (verem kibontása nélkül)Magas költség (stack unwinding, StackTrace rögzítése)
Kompozíciómap/flatMap segítségével — lineáris láncokBeágyazott try-catch — nehezen olvasható
FordítóKimerítő ellenőrzés (switch/when)Csak checked exceptions Java-ban
Végrehajtási folyamatNem szakad meg — a hiba mint értékMegszakad a legközelebbi catch-ig
TesztelésKönnyű: eredmény ellenőrzése, assert isSuccess/isErrorassertThrows és mock objektumok szükségesek
Mikor használdÜzleti validáció, kérési láncok, űrlapokHálózati kapcsolat megszakadása, I/O hibák, rendszerösszeomlások

Gyakorlati szabály: ha a hiba az alkalmazás normál munkafolyamatának része (a felhasználó érvénytelen e-mailt adott meg, nincs elegendő hozzáférési jogosultsága) — használj Result-ot. Ha a hiba kivételes helyzet (a szerver nem válaszol, elfogyott a memória) — használj kivételeket. A mobilfejlesztésben a Result a rétegek határain (UseCase -> ViewModel) és a kivételek a rétegeken belül (API -> Repository) — egy gyakori minta, amely mindkét megközelítés előnyeit ötvözi.

Migrációs stratégia kivételekről Result-ra

A meglévő kivétel-alapú kód Result-ra történő migrációjának fokozatosnak kell lennie. Kezdd a rétegek határaival: csomagold be a throws függvények hívásait Result { try ... } (Swift) vagy runCatching { ... } (Kotlin) kifejezésekbe. Ezután cseréld ki a Repository és UseCase metódusok visszatérési típusát Result/Either-re, miközben a belső implementációt kivételeken hagyod. Az utolsó szakaszban migráld a ViewModel-t: a kivételekkel ellátott UiState helyett használj sealed class UiState<T> (Loading, Success, Error) típust, ahol az Error a domain hibát tárolja, nem a Throwable-t. A fokozatos migráció lehetővé teszi az egyes rétegek külön-külön történő tesztelését globális refaktorálás nélkül.

Gyakran ismételt kérdések

Miben különbözik a Result Type az Optional/Option-tól?

Optional (T?) egy érték jelenlétét vagy hiányát reprezentálja — a nil jelentése “nincs adat”, de nem mondja meg, hogy miért. Result (Success/Failure) nem csak a sikert, hanem a hiba okát is tartalmazza egy konkrét típussal. Használd az Optional-t, amikor az érték hiánya normális (pl. opcionális profilmező), Result-ot — amikor információra van szükséged a hibáról.

Hogyan alakítsunk át egy throws függvényt Result-tá?

Swift-ben használd a Result { try throwingFunc() } kifejezést — a Result konstruktora throws lezárást fogad el. Kotlin-ban — runCatching { throwingFunc() }, amely Result<T>-t ad vissza. Dart-ban — Result<T>.tryCatch(() => throwingFunc()). Ez lehetővé teszi a kivétel-alapú kód egyszerű integrálását Result láncokba.

Hogyan kezeljünk hibát Result-ban információvesztés nélkül?

Használd a mapError (Swift) vagy mapLeft (Either Dart-ban/Kotlin-ban) függvényeket a hiba típusának transzformálásához a sikeres érték megváltoztatása nélkül. Ha mindkét esetet kezelned kell és egyetlen értéket visszaadnod — használd a fold-ot. Naplózáshoz a lánc megszakítása nélkül használd az onFailure (Kotlin) vagy egy előtagolt inspection point-ot.

Használható-e a Result Kotlin-ban korutinokkal?

Igen, de óvatosan. A Kotlin Result<T> nem ajánlott közvetlen visszatérési típusként suspend függvényekhez a K2 fordító és a reflexió sajátosságai miatt. Használd a saját sealed class-odat, a NetworkResult<T>-t (Success, Error, Loading) az állapotok reprezentálásához korutinokban. Várható üzleti logikai hibákhoz az Arrow-ból származó Either egy erősebb alternatíva.

Mi az a fold a Result kontextusában?

fold — egy metódus, amely két callback-et fogad: onSuccess (a sikeres esethez) és onFailure (a hiba esethez), és egyetlen értéket ad vissza bármilyen típusból. Ez a switch kifejezés megfelelője, de magasabb rendű függvény formájában. A fold — a fő kilépési pont a Result láncokból, ahol a Success/Failure-t UiState-vé, felhasználói sztringgé vagy más Result-tá alakítod.

Összefoglalás

  • Result Type — generikus konténer (Success/Failure) a várható hibák biztonságos kezeléséhez verem kibontása nélkül
  • Swift-ben Result<Success, Failure> Failure: Error segítségével kimerítő ellenőrzést biztosít switch-en keresztül type-safe hibákkal
  • Kotlin-ban Result<T> sikert vagy Throwable-t csomagol, runCatching — kényelmes konstruktor throws kódból
  • Dart-ban beépített Result<T> (Dart 3.0) és Either<L, R> a fpdart-ból fejlett kompozícióhoz map/flatMap segítségével
  • Kompozíció map (siker transzformációja) és flatMap (Result függvények lánca) segítségével helyettesíti a beágyazott try-catch-eket
  • Result vs kivételek: Result a várható üzleti hibákhoz, kivételek a váratlan rendszerhibákhoz
  • Használd a Result-ot a rétegek határain a kifejezett és tesztelhető hibakezeléshez a végrehajtási folyamat megszakítása nélkül

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is