2017-10-12 64 views
5

我有一個自定義的結構體,其中包含幾個字段,並且我希望在一個快速的switch語句,所以我可以通過比較其中一個字段與正則表達式來自定義匹配。swift 4:模式將對象與元組相匹配(元組模式不能匹配非元組類型的值)

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包裝明確這樣。

似乎swift有一些神奇的祕訣,用於與元組進行模式匹配。我能在這裏做什麼嗎?

+0

'switch((someInstance.header,someInstance.text))'工作嗎? – vacawama

+0

@vacawama這是一個很酷的想法。我嘗試了它,但不幸的是它沒有工作,仍然有'Tuple模式不能匹配...'錯誤 –

回答

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: ... 
} 
+0

也是一個很酷的想法!不幸的是,在我的實際實現中(並非SO的整理版本),第一個元素是一個CFString,第二個元素是一個String,所以我不能使用數組:--( –

+0

@OrionEdwards'let str = header as String'你可以很容易地將'CFString'轉換爲'String' –

+0

@KleinMioke非常感謝!但是我試圖減少使用它所需的噪音和打字量。在每一行上做一個'as String'會有點失敗 –

0

你可以做一個計算的屬性返回一個元組:

struct MyStruct { 
    let header: String 
    let text: String 

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

然後你就可以根據tuple計算財產switch

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子句中做任何你想要的。