Swift书中有一些例子分别展示了相关值和原始值,有没有办法用两种特征一起定义枚举?
我试图将它们合并,但却出错了:
enum Barcode :String {
case UPCA(Int, Int, Int) = "Order 1" // Enum with raw type cannot have cases with arguments
case QRCode(String) = "Order 2" // Enum with raw type cannot have cases with arguments
}
答案 0 :(得分:35)
是的,这是可能的。枚举可以包含关联值和原始值。 ( Swift 4& 3 )
您的代码存在的问题是您使用简写表示法来RawRepresentable
和定义关联类型。
让我们看看如何分别定义这些:
1)RawRepresentable
(简写符号):
enum Barcode: String {
case UPCA = "order 1"
case QRCode = "order 2"
}
2)相关类型:
enum Barcode {
case UPCA(Int, Int, Int)
case QRCode(String)
}
其中每个都很棒,但如果你的代码片段显示,那么该怎么办呢。
使用关联值定义枚举,然后在扩展名中实现与RawRepresentable
单独的一致性(即不使用简写符号)。
示例:
enum Barcode {
case UPCA(Int, Int, Int)
case QRCode(String)
}
extension Barcode: RawRepresentable {
public typealias RawValue = String
/// Failable Initalizer
public init?(rawValue: RawValue) {
switch rawValue {
case "Order 1": self = .UPCA(1,1,1)
case "Order 2": self = .QRCode("foo")
default:
return nil
}
}
/// Backing raw value
public var rawValue: RawValue {
switch self {
case .UPCA: return "Order 1"
case .QRCode: return "Order 2"
}
}
}
次要细节
在此解决方案中,相关值的默认值,例如从rawValue参数构造枚举时必须提供.UPCA(1,1,1)
。您可以使用相关类型作为支持原始值的一部分 - 这更强大,但会增加一些复杂性。
<强>参考强>
有关该主题的更多信息,请参阅Ole Begemann's优秀的写作。
答案 1 :(得分:13)
这里的答案很棒,但不提供替代方案,所以这里有一个:
我正在尝试为Parse.com的其余API编写一个方便的包装器,老实说,swift强加的这个限制使我编写了更多代码,但最终结果更具可读性:
class Parse {
enum Endpoint {
case signUp(ParseHTTPBody)
case login(ParseHTTPBody)
}
}
extension Parse.Endpoint {
var httpMethod: String {
switch self {
case .signUp, .login:
return "POST"
}
}
var path: String {
switch self {
case .signUp:
return "/1/users"
case .login:
return "/1/login"
}
}
}
注意,现在我httpMethod
和path
而不是rawValue
,这在我的案例中更具可读性:
func setParseEndpoint(endpoint: Parse.Endpoint) -> Self {
URL = NSURL(string: baseURL + endpoint.path)
HTTPMethod = endpoint.httpMethod
return self
}
答案 2 :(得分:5)
从Swift 3开始,你可以同时使用一个枚举。
旧答案:
错误消息似乎非常清楚:您必须选择其中一个。
我不知道它在幕后是如何工作的,所以这是一个猜测,但似乎案例参数存储为一个元组值,其中&#34; Raw Type&#34;否则将存储值
答案 3 :(得分:4)
正如@Jiaaro已经指出的那样,你不能这样做(包括在Beta5中)。
然而,这将是非常有意义的:具有属性值的枚举可以实现为“受歧视的联合”或“变体”(see also wiki "tagged union"),其中“原始值”将扮演“标签”。
那个枚举只会占用任何属性类型的最大大小的空间加上标记的大小(加上对齐的填充)。
答案 4 :(得分:1)
enum Barcode {
case UPCA(Int, Int, Int)// = "Order 1"
case QRCode(String)// = "Order 2"
static func customRawValue(rawValue: String) -> Barcode? {
switch rawValue {
case "Order 1": return Barcode.UPCA(0, 0, 0)
case "Order 2": return Barcode.QRCode("")
default: return nil
}
}
var customRawValue : String {
switch self {
case .UPCA: return "Order 1"
case .QRCode: return "Order 2"
}
}
}
if let barcode = Barcode.customRawValue("Order 1") {
print("Barcode found with custom rawValue: \(barcode)")
print("Custom rawValue: \(barcode.customRawValue)")
}
这有些笨拙,但这个解决方案对我来说很有用!
答案 5 :(得分:0)
处理关联值的优雅方式(即使枚举是间接的):
indirect enum MyEnum {
var value: String? {
return String(describing: self).components(separatedBy: "(").first
}
case greeting(text: String)
case goodbye(bool: Bool)
case hey
case none
}
print(MyEnum.greeting(text: "Howdy").value)
// prints : greeting
现在,您甚至可以像这样使用 value
来实现 Equatable
:
indirect enum MyEnum: Equatable {
static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
lhs.value == rhs.value
}
var value: String? {
return String(describing: self).components(separatedBy: "(").first
}
case greeting(text: String)
case goodbye(bool: Bool)
case hey
case none
}