将项目投射到两个选项之一

Casting an item to either of two options

我想知道一种将项目投射到 Type1Type2 的方法。

为了更清楚,我举个例子

假设我们有两个不同的 struct 继承自 Decodable

struct Decodable1: Decodable { ... }

struct Decodable2: Decodable { ... }

我使用那些 Decodable 来解析从 http 请求中获取的 json。在几个地方,我必须将这些数据用作;

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

有人可以建议一个好的方法吗?

编辑:

此外,除了减少 switch 语句之外,我的意图是轻松到达那些 Decodable 中定义的变量。这意味着无需执行任何 switchif-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可能吗?

如果我没理解错的话,你的问题是重复使用 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()]

根据您的用例(我不清楚),您可能希望考虑 "Either" pattern:

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: [=11=]) })
    }
}

let e = Either<Decodable1, Decodable2>.fromAny(data1)