【问题标题】:Check an enum can be created from a parameter in a switch检查可以从开关中的参数创建枚举
【发布时间】:2019-01-18 14:43:12
【问题描述】:

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

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,并且只有在可以创建的情况下才输入案例,这样我就可以使用创建的那个,而不必创建第二个一个?

【问题讨论】:

  • 你在 switch 中有两次 "a",是错字吗?
  • @RobertDresler,~~这些情况有不同的where谓词,它们不一样。~~哦等等,第二个应该是“c”。
  • 不要太复杂。打开base,对于情况“a”和“c”,请执行if let p = parameter, let foo = Foo(rawValue: p)(或guard let ...)。
  • 或者跳过switch语句,只使用if的:if base == "a", let p = parameter, let foo = Foo(rawValue: p)

标签: swift enums switch-statement


【解决方案1】:

不要把它弄得太复杂。打开base 值,并在需要时处理parameter,使用ifguard 和可选绑定:

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?) 案例,然后仍然检查剩余案例。

【讨论】:

  • 另外,在 temp p 变量中不需要,只需 let foo/bar = parameter.flatMap(Foo/Bar.init) 即可。
  • @user28434:这是另一种选择,但我发现这更容易阅读(当然基于意见)。
【解决方案2】:

另一种替代方法是 switchFooBar 初始化器上:

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 上的表达式也可能增加。

【讨论】:

    猜你喜欢
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    相关资源
    最近更新 更多