将项目投射到两个选项之一
Casting an item to either of two options
我想知道一种将项目投射到 Type1
或 Type2
的方法。
为了更清楚,我举个例子
假设我们有两个不同的 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
中定义的变量。这意味着无需执行任何 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
可能吗?
如果我没理解错的话,你的问题是重复使用 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)
我想知道一种将项目投射到 Type1
或 Type2
的方法。
为了更清楚,我举个例子
假设我们有两个不同的 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
中定义的变量。这意味着无需执行任何 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
可能吗?
如果我没理解错的话,你的问题是重复使用 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)