当在枚举中找不到值时抛出异常而不是返回 nil

Jer*_*kar 1 generics enums swift

我有一个数组,是从服务器发送的 JSON 中解码的。我想在一行代码中检索节点的值并将其转换为枚举值。可能会发生几个错误:(1)节点不存在,(2)节点值不是字符串(我的枚举只有字符串原始值),或者(3)提供的字符串不适合枚举中的任何现有值。

目前,我对 Dictionary 进行了扩展,使我能够将 (1) 和 (2) 放在一行中用于枚举以外的其他内容,并且如果发生错误,则可以轻松传播错误:

struct MemberOptions : MyDecodable
{
    var name:String 
    var age:Int 
    var facebookAccount:FacebookAccount


    init(from array:[String:Any]) throws 
    {
        // throw exception if node name doesn't exist, is json<null> or if it's value is not castable to the providen parameter (raw types or more complex object implementing MyDecodable protocol)
        name = try array.getSafe("name", String.self)
        age = try array.getSafe("age", Int.self) 
        facebookAccount = try array.getSafe("fb", FacebookAccount.self) 

    }
   
}
Run Code Online (Sandbox Code Playgroud)

现在是棘手的部分:我想要 (3) 来表示枚举,也就是说,对于给定的枚举,如果提供的字符串原始值不是已知的枚举值,则在一行中传播错误。我看到如果原始字符串值不存在,枚举的默认 init 返回 nil 。我希望它抛出异常。

当然,我可以为所有枚举创建一个会引发异常的 init,但这不是通用的,这将是多余的代码。当然,我也可以在我的商务课程中这样做:

if let enumVal = MyEnum(rawValue: try array.getSafe("enumKey", String.self))
{
     self.enumVal = enumVal 
} 
else 
{
    throw ValueNotPresentException()
} 
Run Code Online (Sandbox Code Playgroud)

但它仍然不够通用,我必须为我想要检索的每个枚举编写这 4 行。

我想要的是所有枚举上的一些共享函数,getSafely(raw: myRawString) throws如果原始值不存在,类似的函数会抛出异常,而不是返回 nil。然后我可以将 (1) (2) 和 (3) 写在一行中,而不必编写冗余代码:

enumProp = try EnumType.getSafely(fromRaw: try array.getSafely("key", String.self)) 
Run Code Online (Sandbox Code Playgroud)

有没有办法在 Swift 中制作这样一个通用系统(可能使用枚举协议或一些反射)?你会怎么处理?

Leo*_*bus 5

您可以扩展RawRepresentable并创建一个抛出异常Error而不是返回的初始值设定项nil

enum Exception: Error {
    case valueNotPresent
}
Run Code Online (Sandbox Code Playgroud)
extension RawRepresentable {
    init(_ rawValue: RawValue) throws {
        guard let value = Self(rawValue: rawValue) else {
            throw Exception.valueNotPresent
        }
        self = value
    }
}
Run Code Online (Sandbox Code Playgroud)

游乐场测试:

enum FacebookAccount: String {
    case a, b, c
}

do {
    let fbAccount = try FacebookAccount("d")
    print(fbAccount)
} catch {
    print(error)  // "valueNotPresent\n"
}
Run Code Online (Sandbox Code Playgroud)