Last active
August 24, 2018 05:41
-
-
Save nteissler/a9d2b00beddcc309445ebebf1a373b49 to your computer and use it in GitHub Desktop.
Pro Pattern Matching
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
// Swift 4.2 Xcode 10 | |
//: ## Optional Patterns | |
func aLegacyObjcFunction() -> String! { | |
return "I wasn't annotated with modern objc conventions!" | |
} | |
func myFunction() -> String { | |
let optionalString = aLegacyObjcFunction() | |
// Compiles in Swift 4.1, Error in Swift 4.2 | |
// Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'? | |
// return optionalString | |
switch optionalString { | |
case let output?: | |
return "\(output) is a `String`." | |
case nil: | |
return "Phew, that could have been segfault." | |
} | |
} | |
//: ## Type Casting and Enumeration Patterns | |
enum Error: Swift.Error { | |
case badError(code: Int) | |
case closeShave(explanation: String) | |
case unknown | |
case fatal | |
} | |
enum OtherError: Swift.Error { | |
case base | |
} | |
func makeURLRequest() throws { } | |
func getUserDetails() { | |
do { | |
try makeURLRequest() | |
} | |
// Enumeration Case Pattern with where clause | |
catch Error.badError(let code) where code == 50 { | |
print("\(code)") | |
} | |
// Enumeration Case Pattern with associated value | |
catch Error.closeShave(let explanation) { | |
print("There's an explanation! \(explanation)") | |
} | |
// Type matching pattern | |
catch let error as OtherError { | |
print("This \(error) is a base error") | |
} | |
// Type Matching Pattern | |
catch is Error { | |
print("We don't want to know much more, it must be fatal or unkown") | |
} | |
// is Swift.Error. The compiler gives us the variable error for free here | |
catch { | |
print(error) | |
} | |
} | |
//: ## If, While, Guard, For-In | |
let stringAndInt: (String, Int?) = ("Seven", 7) | |
if case (_, let value?) = stringAndInt { | |
print("The int value of the string is \(value)") | |
} | |
guard case (_, let value?) = stringAndInt else { | |
print("We have no value, exiting early.") | |
exit(0) | |
} | |
var guess: Int = 0 | |
while case 0...10 = guess { | |
// Playgrounds don't support reading from stdin | |
//guess = Int(readLine()!)! | |
guess = 11 | |
} | |
print("You guessed a number out of the range!") | |
//: ## A Custom Expression Pattern with Regex | |
struct Regex: ExpressibleByStringLiteral, Equatable { | |
fileprivate let expression: NSRegularExpression | |
init(stringLiteral: String) { | |
do { | |
self.expression = try NSRegularExpression(pattern: stringLiteral, options: []) | |
} catch { | |
print("Failed to parse \(stringLiteral) as a regular expression, falling back to match everything") | |
self.expression = try! NSRegularExpression(pattern: ".*", options: []) | |
} | |
} | |
fileprivate func match(_ input: String) -> Bool { | |
let result = expression.rangeOfFirstMatch(in: input, options: [], range: NSRange(input.startIndex..., in: input)) | |
return !NSEqualRanges(result, NSMakeRange(NSNotFound, 0)) | |
} | |
static let email: Regex = """ | |
^(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+)*|\"(?:[\\x01-\\x08\ | |
\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@\ | |
(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0\ | |
-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?\ | |
:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7\ | |
f])+)\\])$ | |
""" | |
static let phone: Regex = "^(\\+\\d{1,2}\\s)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$" | |
} | |
extension Regex { | |
static func ~=(pattern: Regex, value: String) -> Bool { | |
return pattern.match(value) | |
} | |
} | |
let input = Bool.random() ? "nerd@bignerdranch.com" : "(770) 817-6373" | |
switch input { | |
case Regex.email: | |
print("Send \(input) and email!") | |
case Regex.phone: | |
print("Give Big Nerd Ranch a call at \(input)") | |
default: | |
print("An unknown format.") | |
} | |
//: ## Switching on a Pointer Value | |
var emailTextField: UITextField! | |
var phoneTextField: UITextField! | |
var passwordTextField: UITextField! | |
func validateEmail() -> Bool { return false } | |
func validatePassword() -> Bool { return false } | |
func validatePhone() -> Bool { return false } | |
class MyDelegate: NSObject, UITextFieldDelegate { | |
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { | |
switch textField { | |
case emailTextField: | |
return validateEmail() | |
case phoneTextField: | |
return validatePhone() | |
case passwordTextField: | |
return validatePassword() | |
default: preconditionFailure("Unaccounted for Text Field") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment