Result Type: Was es ist, der Result-Container-Typ und wie es in der mobilen Entwicklung funktioniert

Autor: IT Sectr Veröffentlicht: 2026-05-26 Lesezeit: 9 Min.

Result Type — ein Container-Typ, der das Ergebnis einer Operation darstellt, die mit Erfolg (Success) oder Fehler (Failure) abgeschlossen werden kann. Im Gegensatz zu Ausnahmen übergibt Result den Fehler als normalen Wert ohne Stack-Entwicklung, was die Behandlung erwarteter Fehler sicherer und komponierbarer macht. Laut Apple Swift Documentation (2026) ermöglicht Result<Success, Failure> in Swift das Verketten von Operationen mit automatischer Fehlerbehandlung durch map und flatMap, ohne die Programmausführung zu unterbrechen.

Wichtige Punkte

  • Result Type — ein generischer Container mit zwei Zuständen: Success (Daten) und Failure (Fehler), ohne Stack-Entwicklung
  • In Swift Result<Success, Failure> — ein eingebauter Typ mit den Methoden map, flatMap, mapError und get
  • In Kotlin Result<T> stellt Erfolg oder Throwable dar, mit den Funktionen getOrNull, getOrDefault, fold
  • In Dart ist der Standard Result<T> seit Dart 3.0 verfügbar, ebenso Either aus dem Paket fpdart
  • Komposition durch map und flatMap ermöglicht das Kombinieren mehrerer Operationen, die Result zurückgeben, ohne verschachtelte Prüfungen

Was ist Result Type?

Result Type ist ein generischer Typ, der das Ergebnis einer Operation kapselt, die entweder erfolgreich sein oder fehlschlagen kann. Im Gegensatz zu Ausnahmen, bei denen ein Fehler den normalen Ablauf unterbricht und eine Stack-Entwicklung erfordert, um einen catch-Block zu finden, übergibt Result den Fehler als normalen Wert — der Aufrufer erhält immer ein Objekt und entscheidet selbst, wie er damit umgeht. Dies ist besonders nützlich für erwartete Fehler: ungültige Eingabe, Geschäftsregeln, Serverablehnung, bei denen Ausnahmen ein zu schwerer Mechanismus wären.

Das Konzept von Result stammt aus der funktionalen Programmierung, wo ähnliche Typen Either (oder Left/Right) genannt werden. In Swift wurde Result mit Swift 5.0 zum Standardtyp; in Kotlin erschien Result<T> in der Standardbibliothek; in Dart 3.0 wurde das integrierte Result<T> eingeführt. Jede Implementierung stellt Methoden zur Arbeit mit dem Container bereit: map (Transformation des Erfolgswerts), flatMap (Verkettung von Result-Funktionen), mapError (Transformation des Fehlers), fold (Behandlung beider Fälle). Result Type ist ein Eckpfeiler der funktionalen Fehlerbehandlung in der mobilen Entwicklung, eine Alternative zu try-catch für erwartete Szenarien.

Der Hauptvorteil von Result ist die Komponierbarkeit. Sie können mehrere Operationen, die jeweils fehlschlagen können, zu einer einzigen Kette ohne verschachtelte try-catch-Blöcke kombinieren. Wenn eine Operation in der Kette mit Failure fehlschlägt, wird die gesamte Kette unterbrochen und gibt Failure zurück — ohne eine einzige if-Bedingung oder catch-Block. Dies macht den Code linear und lesbar, insbesondere in Szenarien mit mehreren sequenziellen API-Anfragen oder Geschäftsregelprüfungen.

Result in Swift

In Swift ist Result<Success, Failure> ein Enum mit zwei Fällen: .success(Success) und .failure(Failure), wobei Failure durch das Error-Protokoll eingeschränkt ist. Swift Result ist ein voll funktionaler Typ mit den Methoden map, flatMap, mapError und get. get ist eine besondere Methode: Sie gibt den Success-Wert zurück, wenn das Ergebnis erfolgreich ist, und wirft den Fehler, wenn es Failure ist. Dies ermöglicht es Result, als Brücke zwischen funktionalen und ausnahmebasierten Stilen zu fungieren: Behandlung durch map/flatMap in einer Kette und am Ende get mit do-catch zur Integration mit throws-Code.

Result-Enum und erschöpfender Switch

Swift Result ist ein Enum mit generischen Parametern, was es dem Compiler ermöglicht, eine erschöpfende Behandlung durch switch oder do-catch zu erzwingen. Wenn Sie dem NetworkError-Enum einen neuen Fall hinzufügen, erzeugt der Compiler einen Fehler in allen switch-Ausdrücken, in denen dieser Fall nicht behandelt wird. Erschöpfende Prüfung ist der Hauptvorteil von Result gegenüber Ausnahmen: Der Compiler garantiert, dass alle möglichen Fehler zur Build-Zeit berücksichtigt werden. Im Gegensatz dazu werden Ausnahmen in Swift nicht vom Compiler geprüft (nur throws wird deklariert, aber nicht der Fehlertyp).

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

// Verwendung mit switch
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> ermöglicht die Typisierung des Fehlers auf Typebene: Die Funktion fetchUser gibt Result<User, NetworkError> zurück, wobei NetworkError ein konkreter Enum mit drei Fällen ist. Der Aufrufer behandelt jeden Fall über switch mit erschöpfender Abdeckung — der Compiler prüft, dass alle Varianten behandelt wurden. Erschöpfender Switch ist ein wesentlicher Vorteil von Result gegenüber Ausnahmen: Der Compiler garantiert, dass Sie nicht vergessen, .badURL, .requestFailed oder .decodingFailed zu behandeln. Bei Ausnahmen verlangt der Compiler keine Behandlung, und ein fehlender catch(.badURL) kann leicht in der Code-Review übersehen werden.

Result in Kotlin

In Kotlin ist Result<T> ein eingebauter Typ aus der Standardbibliothek, der Erfolg (T) oder Fehler (Throwable) darstellt. Im Gegensatz zu Swift erlaubt Kotlin Result nicht die Angabe eines konkreten Fehlertyps — nur Throwable. Dies dient der Einfachheit, erfordert aber zusätzliche Fehlertyp-Prüfung durch den when-Ausdruck. Kotlin Result unterstützt die Funktionen fold (beide Fälle behandeln), getOrNull (Erfolg oder null), getOrDefault (Erfolg oder Standardwert), map, recover, andThen. Eine Besonderheit von Kotlin: Result ist nicht für die direkte Propagation über Funktionsgrenzen hinweg gedacht — es kann nicht ohne zusätzliche Anpassung als Rückgabetyp für Android SDK-Methoden oder die Kotlin Coroutines API verwendet werden.

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 ist ein praktischer Wrapper in Kotlin, der jede Ausnahme abfängt und Result.failure zurückgibt. validateEmail gibt je nach Validierung Result.success oder Result.failure zurück. fold behandelt beide Fälle kompakt: Bei Success wird die nächste Validierungsfunktion aufgerufen; bei Failure wird SignupResult.Error zurückgegeben. Wichtig: Kotlin Result ist nicht für die Speicherung in data class-Feldern oder die direkte Übertragung über suspend-Funktionsgrenzen hinweg gedacht — verwenden Sie benutzerdefinierte versiegelte Klassen (Success/Error/Loading) zur Darstellung von UI-Zuständen in Jetpack Compose oder MVVM.

Result in Dart und Flutter

Seit Dart 3.0 enthält die Standardbibliothek ein integriertes Result<T> — eine versiegelte Klasse mit zwei Konstruktoren: T.ok() (Erfolg) und Error.error() (Fehler mit Object und StackTrace). Vor Dart 3.0 verwendeten Flutter-Entwickler Either<L, R> aus dem Paket dartz oder benutzerdefinierte versiegelte Klassen. Das integrierte Result in Dart ist minimalistisch: Es bietet map/flatMap nicht direkt an — diese Funktionen müssen über when oder mit Erweiterungsmethoden implementiert werden. Für eine ernsthafte funktionale Behandlung bleibt Either von fpdart mit Unterstützung für map, flatMap, mapLeft, fold, andThen und bind-Operatoren die leistungsfähigere Lösung.

Either von fpdart

Either<L, R> ist ein links-biasierter Typ aus dem Paket fpdart, wobei Left der Fehler und Right der Erfolg ist. Im Gegensatz zum integrierten Result<T> typisiert Either den Fehler auf der Ebene des Typparameters (L), was eine Fehlertypunterscheidung zur Compile-Zeit ermöglicht. Das Paket fpdart bietet einen vollständigen Satz funktionaler Kombinatoren: map (Right -> Right), mapLeft (Left -> Left), flatMap (bind — verschachteltes Either), andThen (Verkettung ohne Transformation), fold (Austritt aus Either), getOrElse (Standardwert). Für Flutter-Anwendungen mit funktionalem Ansatz ist Either der De-facto-Standard.

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

// Verwendung mit fold
final result = await service.fetchUser('42');
result.fold(
    (left)  => showError(left.message),
    (right) => showUser(right),
);

Either<L, R> von fpdart ist ein links-biasierter Typ: Left — Fehler, Right — Erfolg. fetchUser gibt Either<AppError, User> zurück, wobei AppError eine versiegelte Klasse mit konkreten Fehlertypen (serverError, networkError) ist. fold behandelt beide Fälle: der erste Callback für Left (Fehler), der zweite für Right (Erfolg). In Dart 3.0 unterstützt das integrierte Result ebenfalls fold, bietet aber kein map/flatMap. Für Ketten bietet Either von fpdart map, flatMap (bind), mapLeft, andThen — einen vollständigen Satz funktionaler Kombinatoren für die Fehlerkomposition.

Result-Komposition mit map und flatMap

Der Hauptvorteil von Result gegenüber Ausnahmen ist die Komposition. Wenn Sie mehrere Operationen haben, die jeweils fehlschlagen können, können Sie sie mit map und flatMap verketten, ohne ein einziges verschachteltes if oder try-catch. map transformiert den Erfolgswert: Result.success(x) -> Result.success(f(x)). flatMap (auch bind oder andThen genannt) ist für Fälle, in denen die Transformation selbst ein Result zurückgibt: Result.success(x) -> f(x) -> Result<Y>. Wenn ein Schritt mit Failure fehlschlägt, werden nachfolgende Operationen nicht ausgeführt — die Kette wird unterbrochen.

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

// Komposition mit flatMap (andThen in fpdart)
val result = validateToken("abc123")
    .flatMap { fetchProfile("42") }
    .map { it.name }
    .getOrElse { "Guest" }

println(result) // "Alice"

Kette: validateToken -> fetchProfile -> map name -> getOrElse „Gast“. Wenn validateToken Left (InvalidToken) zurückgibt, wird die Kette unterbrochen und gibt „Gast“ zurück. Wenn fetchProfile Left (UserNotFound) zurückgibt — ebenfalls „Gast“. Wenn beide Operationen erfolgreich sind — der Profilname. flatMap ermöglicht das Kombinieren von Either-Funktionen, die jeweils fehlschlagen können, zu einer einzigen linearen Kette. Im traditionellen Ausnahmestil würde derselbe Code zwei verschachtelte try-catch oder null-Prüfungen erfordern. getOrElse am Ende ist der Austrittspunkt aus der Komposition, der einen Standardwert für den Failure-Fall bereitstellt.

Result vs. Ausnahmen: Wann man was wählt

Result und Ausnahmen schließen sich nicht gegenseitig aus. Jeder hat seinen eigenen Bereich, und in einer gut gestalteten mobilen Anwendung werden beide verwendet. Die Wahl hängt davon ab, ob der Fehler erwartet oder unerwartet ist. Result ist für erwartete Fehler, die Teil der Geschäftslogik sind: ungültige E-Mail, unzureichende Mittel, Ratenlimit überschritten. Ausnahmen sind für unerwartete Systemfehler: Netzwerkverlust, OutOfMemoryError, NullPointerException (die nicht auftreten sollten, aber doch auftreten).

KriteriumResult TypeAusnahmen (Exception/Error)
FehlertypErwartet (Geschäftslogik)Unerwartet (System)
LeistungNiedrige Kosten (ohne Stack-Entwicklung)Hohe Kosten (Stack-Entwicklung, StackTrace-Erfassung)
KompositionMit map/flatMap — lineare KettenVerschachtelte try-catch — schwer lesbar
CompilerErschöpfende Prüfung (switch/when)Nur geprüfte Ausnahmen in Java
AusführungsflussNicht unterbrochen — Fehler als WertUnterbrochen bis zum nächsten catch
TestenEinfach: Ergebnis prüfen, isSuccess/isError bestätigenErfordert assertThrows und Mock-Objekte
Wann verwendenGeschäftsvalidierung, Anforderungsketten, FormulareNetzwerkverlust, E/A-Fehler, Systemabstürze

Praktische Regel: Wenn der Fehler Teil des normalen Arbeitsablaufs der Anwendung ist (Benutzer hat eine ungültige E-Mail eingegeben, unzureichende Berechtigungen) — verwenden Sie Result. Wenn der Fehler eine außergewöhnliche Situation ist (Server antwortet nicht, Speicher erschöpft) — verwenden Sie Ausnahmen. In der mobilen Entwicklung ist Result an Schichtgrenzen (UseCase -> ViewModel) und Ausnahmen innerhalb der Schichten (API -> Repository) ein gängiges Muster, das die Vorteile beider Ansätze kombiniert.

Migrationsstrategie von Ausnahmen zu Result

Die Migration bestehender ausnahmebasierter Codebasis zu Result sollte schrittweise erfolgen. Beginnen Sie mit Schichtgrenzen: Wickeln Sie throws-Funktionsaufrufe in Result { try ... } (Swift) oder runCatching { ... } (Kotlin). Ersetzen Sie dann den Rückgabetyp von Repository- und UseCase-Methoden durch Result/Either, wobei Sie die interne Implementierung bei Ausnahmen belassen. Im letzten Schritt migrieren Sie das ViewModel: Verwenden Sie anstelle von UiState mit Ausnahmen eine versiegelte Klasse UiState<T> (Loading, Success, Error), wobei Error einen Domänenfehler speichert, kein Throwable. Die schrittweise Migration ermöglicht das Testen jeder Schicht einzeln ohne globale Refaktorisierung.

Häufig gestellte Fragen

Wie unterscheidet sich Result Type von Optional/Option?

Optional (T?) stellt das Vorhandensein oder Fehlen eines Werts dar — nil bedeutet „keine Daten“, erklärt aber nicht warum. Result (Success/Failure) enthält nicht nur den Erfolg, sondern auch den Fehlergrund mit einem konkreten Typ. Verwenden Sie Optional, wenn Abwesenheit normal ist (z. B. ein optionales Profilfeld), und Result, wenn Sie Fehlerinformationen benötigen.

Wie konvertiert man eine throws-Funktion in Result?

Verwenden Sie in Swift Result { try throwingFunc() } — der Result-Konstruktor nimmt einen throws-Closure. In Kotlin verwenden Sie runCatching { throwingFunc() }, das Result<T> zurückgibt. In Dart verwenden Sie Result<T>.tryCatch(() => throwingFunc()). Dies ermöglicht die einfache Integration von ausnahmebasiertem Code in Result-Ketten.

Wie behandelt man einen Fehler in Result ohne Informationsverlust?

Verwenden Sie mapError (Swift) oder mapLeft (Either in Dart/Kotlin), um den Fehlertyp zu transformieren, ohne den Erfolgswert zu ändern. Wenn Sie beide Fälle behandeln und einen einzelnen Wert zurückgeben müssen, verwenden Sie fold. Für die Protokollierung ohne Unterbrechung der Kette verwenden Sie onFailure (Kotlin) oder einen Präfix-Inspektionspunkt.

Kann Result in Kotlin mit Coroutinen verwendet werden?

Ja, aber mit Vorsicht. Kotlin Result<T> wird aufgrund von Besonderheiten des K2-Compilers und der Reflexion nicht als Rückgabetyp für suspend-Funktionen direkt empfohlen. Verwenden Sie Ihre eigene versiegelte Klasse NetworkResult<T> (Success, Error, Loading) zur Darstellung von Zuständen in Coroutinen. Für erwartete Fehler in der Geschäftslogik ist Either von Arrow eine leistungsfähigere Alternative.

Was ist fold im Kontext von Result?

fold ist eine Methode, die zwei Callbacks akzeptiert: onSuccess (für den Erfolgsfall) und onFailure (für den Fehlerfall), und einen einzelnen Wert beliebigen Typs zurückgibt. Es ist das Äquivalent eines switch-Ausdrucks, aber als Funktion höherer Ordnung. fold ist der Hauptaustrittspunkt aus Result-Ketten, wo Sie Success/Failure in UiState, eine benutzerorientierte Zeichenfolge oder ein anderes Result umwandeln.

Zusammenfassung

  • Result Type — ein generischer Container (Success/Failure) zur sicheren Behandlung erwarteter Fehler ohne Stack-Entwicklung
  • In Swift bietet Result<Success, Failure> mit Failure: Error erschöpfende Prüfung durch switch mit typsicheren Fehlern
  • In Kotlin umschließt Result<T> Erfolg oder Throwable, runCatching ist ein praktischer Konstruktor aus throws-Code
  • In Dart integriertes Result<T> (Dart 3.0) und Either<L, R> von fpdart für erweiterte Komposition mit map/flatMap
  • Komposition durch map (Erfolg transformieren) und flatMap (Result-Funktionen verketten) ersetzt verschachtelte try-catch
  • Result vs. Ausnahmen: Result für erwartete Geschäftsfehler, Ausnahmen für unerwartete Systemausfälle
  • Verwenden Sie Result an Schichtgrenzen für explizite und testbare Fehlerbehandlung ohne Unterbrechung des Ausführungsflusses

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch