我有一个像这样的 Swift 枚举:
public enum AnimationType {
case position(Float)
case position([Keyframe<Float>])
case scale(Float)
case scale([Keyframe<Float>])
case rect(CGRect)
case rect([Keyframe<CGRect>])
case transform(CGAffineTransform)
case transform([Keyframe<CGAffineTransform>])
...
...
}
正如我们所见,每种类型都有两个可能的值 - 类型 T 的固定值或值类型 T 的关键帧数组 ([Keyframe])。我想知道我是否可以做些什么来避免在枚举中重复相同的名称并合并两个枚举案例类型?或者我以错误的方式建模?
最佳答案
我将针对每种变体使用 Kind
枚举类型来解决这个问题。
public enum AnimationType {
public enum Kind<Value> {
case scalar(Value)
case keyframes([Keyframe<Value>])
}
case position(Kind<Float>)
case scale(Kind<Float>)
case rect(Kind<CGRect>)
case transform(Kind<CGAffineTransform>)
}
用法:
let anim1 = AnimationType.position(.scalar(10))
let anim2 = AnimationType.position(.keyframes([Keyframe(10)]))
获取值:
switch anim1 {
case .position(let kind):
switch kind {
case .scalar(let value):
print("value: \(value)")
case .keyframes(let keyframes):
print("keyframes: \(keyframes)")
}
default: // You would implement the rest
break
}
switch anim1 {
case .position(.scalar(let value)):
print("value: \(value)")
case .position(.keyframes(let keyframes)):
print("keyframes: \(keyframes)")
default: // You would implement the rest
break
}
if case .position(.scalar(let value)) = anim1 {
print("value: \(value)")
}
您还可以添加 Codable
一致性:
public struct Keyframe<Value: Codable> {
let value: Value
init(_ value: Value) {
self.value = value
}
}
extension Keyframe: Codable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(value)
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
value = try container.decode(Value.self)
}
}
public enum AnimationType {
public enum Kind<Value: Codable> {
case scalar(Value)
case keyframes([Keyframe<Value>])
}
case position(Kind<Float>)
case scale(Kind<Float>)
case rect(Kind<CGRect>)
case transform(Kind<CGAffineTransform>)
}
extension AnimationType.Kind: Codable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .scalar(let value): try container.encode(value)
case .keyframes(let keyframes): try container.encode(keyframes)
}
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let scalar = try? container.decode(Value.self) {
self = .scalar(scalar)
return
}
if let keyframes = try? container.decode([Keyframe<Value>].self) {
self = .keyframes(keyframes)
return
}
// You should throw error here instead
fatalError("Failed to decode")
}
}
extension AnimationType: Codable {
private enum CodingKeys: CodingKey {
case position
case scale
case rect
case transform
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .position(let kind): try container.encode(kind, forKey: .position)
case .scale(let kind): try container.encode(kind, forKey: .scale)
case .rect(let kind): try container.encode(kind, forKey: .rect)
case .transform(let kind): try container.encode(kind, forKey: .transform)
}
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let position = try? container.decode(Kind<Float>.self, forKey: .position) {
self = .position(position)
return
}
if let scale = try? container.decode(Kind<Float>.self, forKey: .scale) {
self = .scale(scale)
return
}
if let rect = try? container.decode(Kind<CGRect>.self, forKey: .rect) {
self = .rect(rect)
return
}
if let transform = try? container.decode(Kind<CGAffineTransform>.self, forKey: .transform) {
self = .transform(transform)
return
}
// You should throw error here instead
fatalError("Failed to decode")
}
}
示例编码:
do {
let data = try JSONEncoder().encode(anim1)
if let str = String(data: data, encoding: .utf8) {
print(str)
// Prints: {"position":10}
}
} catch {
print(error)
}
与 anim2
相同的事情返回 {"position":[10]}
。
关于ios - Swift 枚举不同类型的关联值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69036422/