检查可以从开关中的参数创建枚举

时间:2019-01-18 14:43:12

标签: swift enums switch-statement

我有一个类似...的枚举

enum MyEnum {
    case a(Foo)
    case b
    case c(Bar)

    enum Foo: String {
        case one
        case two
    }

    enum Bar: String {
        case three
        case four
    }
}

我正在尝试为此创建一个可失败的初始化函数,以便您可以像这样调用它...

MyEnum(base: "a", parameter: "one")

MyEnum(base: "b", parameter: nil)

我已经像这样工作了(但是笨拙)...

init?(base: String, parameter: String?) {
    switch (base, parameter) {
    case ("a", let p?) where Foo(rawValue: p) != nil:
        self = .a(Foo(rawValue: p)!)
    case ("b", _):
        self = .b
    case ("c", let p?) where Bar(rawValue: p) != nil:
        self = .c(Bar(rawValue: p)!)
    default:
        return nil
    }
}

这将打开base,然后在输入大小写之前检查是否可以创建下一个值。

但是,我现在必须创建两次FooBar,然后强制打开第二个包装。

有没有一种方法来创建开关盒以创建FooBar,并且仅在可以创建开关盒的情况下才输入该盒,这样我就可以使用创建的开关盒而不必创建第二个?

2 个答案:

答案 0 :(得分:5)

不要太复杂。开启base值,并在需要时使用parameterif以及可选的绑定来处理guard

init?(base: String, parameter: String?) {
    switch base {
    case "a":
        guard let p = parameter, let foo = Foo(rawValue: p) else { return nil }
        self = .a(foo)
    case "b":
        self = .b
    case "c":
        guard let p = parameter, let bar = Bar(rawValue: p) else { return nil }
        self = .c(bar)
    default:
        return nil
    }
}

易于理解,没有强制展开,并且FooBar值仅创建一次(如果需要)。

这也最小化了测试:例如,MyEnum(base: "a", parameter: nil)将转到"a"情况并返回nil。在您的switch语句中,它将不符合("a", let p?)的情况,然后仍然检查其余的情况。

答案 1 :(得分:0)

另一种替代方法是在switchFoo初始化程序上同时使用Bar

init?(base: String, parameter: String?) {
    switch (base, parameter.flatMap { Foo.init(rawValue: $0) ?? Bar(rawValue: $0) } as Any?) {
    case ("a", let foo as Foo):
        self = .a(foo)
    case ("b", _):
        self = .b
    case ("c", let bar as Bar):
        self = .c(bar)
    default:
        return nil
    }
}

不利之处在于,如果FooBar具有共同的情况,那么您可能无法获得想要的结果。同样,如果案件数量增加,switch上的表达式也可能增加。