Приведение предмета к одному из двух вариантов - PullRequest
0 голосов
/ 04 июля 2018

Я задаюсь вопросом о способе приведения предмета к Type1 или Type2.

Для большей ясности приведу пример

Допустим, у нас есть два разных struct наследования от Decodable

struct Decodable1: Decodable { ... }

struct Decodable2: Decodable { ... }

Я использую эти Decodable s для анализа json, который получен из http запросов. В нескольких местах я должен использовать эти данные как;

let data1 : [Decodable1] = [...]
let data2 : [Decodable2] = [...]
var data : [Decodable] = []

switch mode {
case .one:
   data = data1 as! [Decodable1]
case .two:
   data = data2 as! [Decodable2]
}

Я знаю, что этот путь довольно прост, и я думаю, что было бы не вредно, если бы я реализовал это только в одном месте. Тем не менее, приложение действительно зависит от этой переменной режима (которую я предоставляю как ReSwift State), и в результате я пытаюсь найти более простой способ для этого. Как;

let data = (mode == .one) ? data1 : data2

Конечно, это не работает и бросить type mismatch error

Может кто-нибудь предложить хороший способ сделать это?

EDIT:

Кроме того, мое намерение, помимо сокращения операторов switch, заключается в том, чтобы легко достичь определенных переменных внутри этих Decodable s. Это означает, что мы не делаем никаких операторов switch или if-else.

Это возможно?

EDIT_2:

Я пересматриваю свой вопрос с учетом последних комментариев.

Допустим, у меня есть class;

class MyClass {
   var data1: [Decodable1] = [...]
   var data2: [Decodable2] = [...]
   var mode: Mode = .One
   func myFunc() -> [Decodable] {
      //return either data1 or data2 with respect to the mode and already casted to its type.
   }
}

Возможно ли function подобное?

1 Ответ

0 голосов
/ 04 июля 2018

Если я вас правильно понимаю, ваша проблема заключается в повторном использовании switch - почему бы просто не создать функцию в enum, которая это делает? - например,

// *** OP's code ***
struct Decodable1: Decodable { /*...*/ }
struct Decodable2: Decodable { /*...*/ }
enum Mode { case one, two }

let data1: [Decodable1] = [Decodable1(), Decodable1()]
let data2: [Decodable2] = [Decodable2(), Decodable2()]
var data: [Decodable] = []

var mode: Mode = .one
switch mode {
case .one:
    data = data1 //as! [Decodable1] // cast is unnecessary
case .two:
    data = data2 //as! [Decodable2] // cast is unnecessary
}
print(data) // [__lldb_expr_18.Decodable1(), __lldb_expr_18.Decodable1()]

// *** Suggestion - extend the mode enum to make the choice... ***
extension Mode {
    func which(_ d1: [Decodable1], _ d2: [Decodable2]) -> [Decodable] {
        switch self {
        case .one:
            return data1
        case .two:
            return data2
        }
    }
}
// *** Usage ***
print(mode.which(data1, data2)) // [__lldb_expr_18.Decodable1(), __lldb_expr_18.Decodable1()]

В зависимости от вашего варианта использования (который мне не понятен), вы можете рассмотреть «Любой» шаблон :

enum Either<L, R> {
    case one(L), two(R)
    init(_ left: L) { self = .one(left) }
    init(_ right: R) { self = .two(right) }
}

extension Either {
    internal init?(any: Any) {
        if let left = any as? L {
            self = .one(left)
        } else if let right = any as? R {
            self = .two(right)
        } else {
            return nil
        }
    }
    static func fromAny(_ any: [Any]) -> [Either] {
        return any.compactMap({ Either(any: $0) })
    }
}

let e = Either<Decodable1, Decodable2>.fromAny(data1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...