Есть ли в Kotlin тип результата, такой как Swift

Swift имеет тип Result, который объявлен следующим образом.

enum Result<Success, Failure: Error> {
    case success(Success)
    case failure(Failure)
}

Что можно использовать так:

enum FooError: Error {
    case fizzReason
    case barReason
    case bazReason
}

func returnResult() -> Result<String, FooError> { 
    // ... Just imagine this method returns an error
}

switch returnResult() {
case .success(let string):
    print(s)
case .failure(.fizzReason):
    // do something
case .failure(.barReason):
    // do something
case .failure(.bazReason):
    // do something
}

Есть ли в Kotlin аналогичный тип данных, который можно использовать таким же образом?

Здесь: kotlinlang.org/api/latest/jvm/stdlib/kotlin/-результат

IgorGanapolsky 23.06.2020 20:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
26
1
11 034
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я не знаю, есть ли что-то подобное в Kotlin, но вот реализация, которая должна делать то же самое:

sealed class Result<out Success, out Failure>

data class Success<out Success>(val value: Success) : Result<Success, Nothing>()
data class Failure<out Failure>(val reason: Failure) : Result<Nothing, Failure>()

Фактический пример:

fun echoString(string : String) : Result<String, Exception> {
    return if (string.isEmpty()) {
        Failure(Exception("Error"))
    } else {
        Success(string)
    }
}

fun main(args : Array<String>) {
    when(val result = echoString("string")) {
        is Success -> println(result.value)
        is Failure -> println(result.reason)
    }
}

Kotlin имеет Результат с такими свойствами, как isFailure и успех, которые в основном эквивалентны результату Swift.

Резюме

Result, a type in the Kotlin standard library that is effectively a discriminated union between successful and failed outcome of execution of Kotlin function — Success T | Failure Throwable, where Success T represents a successful result of some type T and Failure Throwable represents a failure with any Throwable exception. For the purpose of efficiency, we would model it as a generic inline class Result in the standard library.

Ограничение

Result нельзя использовать в качестве прямого типа результата функций Kotlin, свойства типа Result также ограничены: например.

fun findUserByName(name: String): Result<User> // ERROR: 'kotlin.Result' cannot be used as a return type 
fun foo(): Result<List<Int>> // ERROR 
fun foo(): Result<Int>? // ERROR
var foo: Result<Int> // ERROR

Однако разрешены функции, которые используют тип Result в универсальных контейнерах или получают результат в качестве типа параметра:

fun findIntResults(): List<Result<Int>> // Ok
fun receiveIntResult(result: Result<Int>) // Ok

Использование (запуск онлайн):

class NumberNotEvenException(var number: Int) : Exception("$number not even") 

fun checkEvenNumbers(list: List<Int>): List<Result<Int>>{

    var returnList = mutableListOf<Result<Int>>()
    for (number in list){
        if (number%2==0){
            returnList.add(Result.success(number))
        }else{
            returnList.add(Result.failure(NumberNotEvenException(number)))
        }
    }
    return returnList
}


fun checkResult(result: Result<Int>){

    result.fold(onSuccess = { number ->
            println("$number is even")

    },onFailure = { 
        if (it is NumberNotEvenException){
            println("${it.number} is Odd")
          }
    })
}

fun main() {
    checkEvenNumbers((0..100).toList()).map {
            checkResult(it)
        }
}

Было бы лучше, если бы цитаты с важной информацией из всех ссылок были добавлены непосредственно в вопрос. Поскольку гиперссылки имеют тенденцию ломаться, а связанная информация может измениться.

user28434'mstep 05.07.2019 11:57

Тип результата в стандартной библиотеке имеет очень мало практического применения, потому что он существует для решения конкретной проблемы и не может использоваться в общем — см. здесь: github.com/Kotlin/KEEP/blob/master/proposals/stdlib/…

Murph 21.02.2020 15:07

Начиная с Kotlin 1.5 эти ограничения сняты, и вы можете свободно использовать монаду Kotlin Result в своем коде, нет необходимости создавать свой запечатанный класс.

HumbleBee 19.07.2021 13:00

Существует несколько реализаций, но две, о которых я знаю (и которые, как я знаю, активно поддерживаются):

  • Котлин-результат - прямой тип результата, полезная гибкость (в README.md есть ссылки на другие реализации)
  • Либо в Стрелке — Kotlin-реализация Both, которую можно использовать в качестве результата. (Стрела имеет много интересных функциональных вещей)

Другие вопросы по теме