Указание пользовательского типа ошибки в типе Result в Swift 5 - PullRequest
2 голосов
/ 21 апреля 2019

Я пытаюсь создать переменную Result с пользовательским типом ошибки со встроенным типом Result в Foundation for Swift 5, но я не могу заставить систему типов понять тип ошибки, которую я хочу выдать.

Код ниже не компилируется.

import Foundation

enum CustomError: String, Error {
    case somethingBadHappened
}

struct Model {
    let value: Int
}

class Request {
    func execute(number: Int, completion: @escaping (Result<Model, CustomError>) -> Void) {
        let result = Result { () throws -> Model in
            if (number < 20) {
                throw CustomError.somethingBadHappened
            } else {
                return Model(value: number)
            }
        }
        // compiler complains here about: Cannot convert value of type 'Result<Model, Error>' to expected argument type 'Result<Model, CustomError>'
        completion(result)
    }
}

let request = Request()
request.execute(number: 19) { result in
    switch result {
    case .success(let value): print("Succeded with \(value)")
    case .failure(let error): print("Failed with \(error)")
    }

}

Изменение подписи закрытия завершения на completion: @escaping (Result<Model, Error>) -> Void работает, но тогда я не использую пользовательский тип ошибки.

Как я могу заставить систему типов понять, что я хотел бы использовать пользовательский тип ошибки?

Ответы [ 3 ]

2 голосов
/ 23 апреля 2019

Извиняюсь за предоставление второго ответа, но для ответа fphilipe должна быть поправка.

Вы можете использовать init(catching:), чтобы сформировать Результат и все же вернуть его как Result<Model, CustomError>.Вот для чего mapError!Например:

enum CustomError: String, Error {
    case somethingBadHappened
}

struct Model {
    let value: Int
}

class Request {
    func execute(number: Int, completion: @escaping (Result<Model, CustomError>) -> Void) {
        let result = Result { () throws -> Model in
            if (number < 20) {
                throw NSError()
            } else {
                return Model(value: number)
            }
        }.mapError { err in
            return CustomError.somethingBadHappened
        }
        completion(result)
    }
}

Я должен выбросить что-то , чтобы сформировать начальный Result<Model, Error>, поэтому я просто выбрасываю NSError в качестве заполнителя.Но затем приходит mapError и превращает это в Result<Model, CustomError>.Сила mapError в том, что она меняет только то, что происходит в случае сбоя.

Таким образом, мы можем сохранить исходную форму кода.

1 голос
/ 21 апреля 2019

Изменение подписи закрытия завершения на completion: @escaping (Result<Model, Error>) -> Void работает, но тогда я не использую пользовательский тип ошибки.

Да, вы!Измените подпись именно таким образом, чтобы вы скомпилировали и запустили свой код.Когда мы доберемся до этой строки:

case .failure(let error): print("Failed with \(error)")

... мы печатаем "Failed with somethingBadHappened".Это доказывает, что ваш экземпляр CustomError.somethingBadHappened прошел нормально.

Если проблема в том, что вы хотите явно отделить свое CustomError, то выделите его явно, как только вы его поймаете:

case .failure(let error as CustomError): print(error)
default : fatalError("oops, got some other error")

Или, если вы хотите еще больше обуздать это и поймать только случай .somethingBadHappened, укажите, что:

case .failure(CustomError.somethingBadHappened): print("Something bad happened")
default : fatalError("oops, got some other error")

Эти примеры являются искусственными, но они демонстрируют то, что они предназначены продемонстрировать - что вашиЭкземпляр CustomError выполняется с полной целостностью.

0 голосов
/ 21 апреля 2019

Просто создайте Result вручную:

let result: Result<Model, CustomError>
if (number < 20) {
    result = .failure(.somethingBadHappened)
} else {
    result = .success(Model(value: number))
}
completion(result)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...