0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ObservableのGenericsにAssociated Values付きEnumを利用したExtensionを作る

Last updated at Posted at 2020-08-23

結論

  • enumにアクセス用のProtocolを適用することで可能.

検討したきっかけ

  • Rxで反復して行なっているAssociated Values付きEnumへの処理を共通化したかった.
    • 新メンバーのイニシャルコスト.(説明する労力、理解してもらう労力)
    • 実装コスト.(数行の労力、レビューの労力)

実践

サンプル: Result型
ケース: SuccessとFailureをそれぞれに分けるオペレータを作る.

問題: Elementの型条件にResultにしたときのコンパイルエラー。

  • ResultのGenericsの指定が必要.
  • 具体的な型を指定すると旨味が少ない.

解決方法:
ResultTypeというアクセス用プロトコルを定義しenum適用する.

以下サンプルコード.

ObservableType+Extension.swift
extension ObservableType where Element: ResultType {
    func mapToSuccess() -> Observable<Element.SuccessType> {
        compactMap { $0.success }
    }

    func mapToFailure() -> Observable<Element.FailureType> {
        compactMap { $0.failure }
    }
}
ResultType.swift
protocol ResultType {
    associatedtype SuccessType
    associatedtype FailureType: Error

    var success: SuccessType? { get }
    var failure: FailureType? { get }
}
Result+Extension.swift
extension Result: ResultType {
    typealias SuccessType = Success
    typealias FailureType = Failure

    var success: Success? {
        switch self {
        case .success(let success):
            return success
        default:
            return nil
        }
    }
    
    var failure: Failure? {
        switch self {
        case .failure(let error):
            return error
        default:
            return nil
        }
    }
}

おまけ

Successをさらに操作する定義など.
Barcodeよりもう少し抽象的なenumであれば実用的かも.

Omake.swift
enum Barcode {
    case qr(String)
    case upc(Int, Int, Int, Int)
    
    var qrValue: String? {
        switch self {
        case .qr(let code):
            return code
        default:
            return nil
        }
    }
    
    var upcValue: (Int, Int, Int, Int)? {
        switch self {
        case .upc(let digit1, let digit2, let digit3, let digit4):
            return (digit1, digit2, digit3, digit4)
        default:
            return nil
        }
    }
}

extension ObservableType where Element: ResultType, Element.SuccessType == Barcode {

    func mapToQrCode() -> Observable<String> {
        compactMap { $0.success?.qrValue }
    }
    
    func mapToUpc() -> Observable<(digit1: Int, digit2: Int, digit3: Int, digit4: Int)> {
        compactMap { $0.success?.upcValue }
    }
}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?