swift 4:模式匹配元组对象元组(元组模式不能匹配非元组类型的值)

时间:2017-10-12 01:36:29

标签: swift pattern-matching swift4

我有一个带有几个字段的自定义结构,我想在一个快速的switch语句中对它进行模式匹配,这样我就可以通过将一个字段与一个正则表达式进行比较来自定义匹配

E.g。鉴于这种结构:

struct MyStruct {
    let header: String
    let text: String
}

喜欢来模式匹配:

switch(someInstance) {
    case ("h1", "[a-z]+"): ...
    case ("h1", "0-9+"): ...
}

我尝试使用模式匹配函数使其工作如下:

func ~=(pattern: (String, String), value: MyStruct) -> Bool {
    return value.header == pattern.0 && value.text.range(of: pattern.1, options: .regularExpression) != nil
}

但是Xcode(9)无法使用此错误进行编译:

元组模式无法匹配非元组类型的值' MyStruct'

我能够取得的最好成绩如下:

struct MatchMyStruct {
    let header: String
    let regex: String

    init(_ header: NSString, _ regex: String) {
        self.header = header
        self.regex = regex
    }
}

func ~=(pattern: MatchMyStruct, value: MyStruct) -> Bool {
    return value.header == pattern.header && value.text.range(of: pattern.regex, options: .regularExpression) != nil
}

这让我模仿这样的匹配:

switch(someInstance) {
    case MatchMyStruct("h1", "[a-z]+"): ...
    case MatchMyStruct("h1", "0-9+"): ...
}

虽然这是有用的,但我更不希望不必像这样明确MatchMyStruct包装器。

似乎斯威夫特有一些神奇的秘诀,用于与元组相匹配的模式。我能在这做什么吗?

2 个答案:

答案 0 :(得分:1)

您可以创建一个计算属性来返回元组:

struct MyStruct {
    let header: String
    let text: String

    var tuple: (String, String) { return (header, text) }
}

然后你可以switch基于tuple计算属性:

switch(someInstance.tuple) {
case ("h1", "[a-z]+"):
    ...
case ("h1", "0-9+"):
    ...
default:
    ...
}

或者,如果您的意图是执行正则表达式匹配:

switch(someInstance.tuple) {
case ("h1", let string) where string.range(of: "^[a-z]+$", options: .regularExpression) != nil:
    print("alphabetic")
case ("h1", let string) where string.range(of: "^[0-9]+$", options: .regularExpression) != nil:
    print("numeric")
default:
    print("other")
}

或者,如果这太多了,你可以为正则表达式模式匹配定义一些字符串函数,例如:

extension String {
    func isMatch(regex pattern: String) -> Bool {
        return range(of: "^" + pattern + "$", options: .regularExpression) != nil
    }
    func contains(regex pattern: String) -> Bool {
        return range(of: pattern, options: .regularExpression) != nil
    }
}

然后:

switch(someInstance.tuple) {
case ("h1", let string) where string.isMatch(regex: "[a-z]+"):
    print("alphabetic")
case ("h1", let string) where string.isMatch(regex: "[0-9]+"):
    print("numeric")
default:
    print("other")
}

或者无论如何都要这样做,但这只是为了说明如果你想要元组匹配,你可以定义计算属性来返回元组,然后在where子句中做任何你想做的事。

答案 1 :(得分:0)

没有解决元组匹配问题,但您可以将模式转换为String数组并仍然享受表达性:

func ~=(pattern: [String], value: MyStruct ) -> Bool {
    return pattern.count == 2 && (value.header as String) == pattern[0] && value.text.range(of: pattern[1], options: .regularExpression) != nil
}

switch someInstance {
    case ["h1", "[a-z]+"]: ...
    case ["h1", "[0-9]+"]: ...
    default: ...
}