Pattern matching negation - swift

How can I negate pattern matching in Swift?
For example I want to do something like:
guard case .wait != currentAction.type else {
return
}
But apparently, I can't. I can do this:
if case .wait = currentAction.type {
return
}
but it's less Swifty. Is there a better way?

Apparently, there is no way to do that right now as of Swift 3.
Things can change in future releases.

You can do this in Swift 3.0.2:
guard currentAction.type != .wait else {
return
}

Related

How to fix deprecated substring(with: )

I'm working through a book exercise where the author has the following code.
func getMatchingString(str: String) -> String? {
if let newMatch = str.range(of:regExFindMatchString,
options:.regularExpression) {
return str.substring(with: newMatch)
} else {
return nil
}
}
the str.substring(with: newMatch) line shows 'substring(with:) is deprecated use String slicing subscript.'
I've tried to figure out what to use to fix this but everything I've tried shows I just don't understand this well enough to fix it. I know that the newMatch is a range object, just can't figure out how to use it effectively.
Any help is greatly appreciated..
Bob
Just use subscripting with the range you obtain from the if let
if let newMatchRange = str.range(of:regExFindMatchString, options:.regularExpression) {
return String(str[newMatchRange])
} else {
return nil
}
You need to translate it to a String as the method actually returns a Substring type, not a String.

Swift return values of different types in function based on conditions

I am new in Swift and have a small question.
I want to build a function which can return values of different types based on the conditions. What return type should I use?? Below is the function. I use "??" as the placeholder. Can anybody help to change the "??" with correct return type?? Thanks!!
fun Req_amt() -> ?? {
if let input_amt = readLine() {
if let amount = Float(input_amt) {
return amount
} else {
return "Bad number."
}
} else {
return "Bad input."
}
}
You could return a Float? with nil to signify an error in general, or you could return a Float but with throws and throw an Error to give further specific info such as “Bad number” or “Bad input”. It sounds like the latter is what you want here.

Matching multiple enums with a single guard case?

I want to match against multiple enums and have something like this:
guard case .north = $0, case .south = $0 else { return }
Is there a way to condense this to a single statement like this?
guard case (. north, . south) = $0 else { return }
The above does not compile, but was hoping I can do something like this. Is there an alternative?
You can put the desired cases into a literal array and use contains to test for a match:
guard [.north, .south].contains($0) else { return }

Unwrap String and check emptiness in the same if statement

I want to achieve this
if let large = imageLinks.large {
if !large.isEmpty {
result = large
}
}
in a single if statement, something like this (this does not compiles)
if let large = imageLinks.large where !large.isEmpty {
result = large
}
Is it possible?
It 's not yet possible.
With the actual Version of swift the if let statement is pretty poor.
But with Swift 1.2 (it will be available in Xcode 6.3).
You will be able to do this:
(SWIFT 1.2)
if let large = imageLinks.large where !large.isEmpty {
result = large
}
But now you cannot.
You can do something like:
if imageLinks.large != nil && !imageLinks.large!.isEmpty {
result = large!;
}
Note:
Swift use "Lazy Evaluation"
If the first part imageLinks.large != nil is false it will not Evaluate the second part, so it will not crash.
But I don't found this solution beautiful (too much force unwrapping).
In swift 4.4, generics to the rescue \o/
public extension Optional where Wrapped == String {
var isEmptyOrNil: Bool { (self ?? "").isEmpty }
}
usage
if nameField.text.isEmptyOrNil {
//doSomething...
}
In Swift 1.1
If you don't like force unwrapping, you can:
if let large = imageLinks.large?.isEmpty == false ? imageLinks.large : nil {
result = large
}
It's not so beautiful anyway :(

unwrapping multiple optionals in if statement

I want to unwrap two optionals in one if statement, but the compiler complaints about an expected expression after operator at the password constant.
What could be the reason?
if let email = self.emailField?.text && let password = self.passwordField?.text
{
//do smthg
}
Done in Swift.
Great news. Unwrapping multiple optionals in a single line is now supported in Swift 1.2 (XCode 6.3 beta, released 2/9/15).
No more tuple/switch pattern matching needed. It's actually very close to your original suggested syntax (thanks for listening, Apple!)
if let email = emailField?.text, password = passwordField?.text {
}
Another nice thing is you can also add where for a "guarding condition":
var email: String? = "baz#bar.com"
var name: String? = "foo"
if let n = name, e = email where contains(e, "#") {
println("name and email exist, email has #")
}
Reference: XCode 6.3 Beta Release Notes
Update for Swift 3:
if let email = emailField?.text, let password = passwordField?.text {
}
each variable must now be preceded by a let keyword
How about wrapping the optionals in a tuple and using switch to pattern match?
switch (self.emailField?.text, self.passwordField?.text) {
case let (.Some(email), .Some(password)):
// unwrapped 'email' and 'password' strings available here
default:
break
}
It's definitely a bit noisier, but at least it could also be combined with a where clause as well.
The usage
if let x = y {
}
is not equivalent to
if (let x = y) { // this is actually not allowed
}
"if let" is effectively a two-word keyword, which is equivalent to
if y != nil {
let x = y!
// rest of if let block
}
Before Swift 1.2
Like #James, I've also created an unwrap function, but this one uses the existing if let for control flow, instead of using a closure:
func unwrap<T1, T2>(optional1: T1?, optional2: T2?) -> (T1, T2)? {
switch (optional1, optional2) {
case let (.Some(value1), .Some(value2)):
return (value1, value2)
default:
return nil
}
}
This can be used like so:
if let (email, password) = unwrap(self.emailField?.text, self.passwordField?.text)
{
// do something
}
From: https://gist.github.com/tomlokhorst/f9a826bf24d16cb5f6a3
Note that if you want to handle more cases (like when one of the two fields is nil), you're better off with a switch statement.
Swift 4
if let suggestions = suggestions, let suggestions1 = suggestions1 {
XCTAssert((suggestions.count > suggestions1.count), "TEST CASE FAILED: suggestion is nil. delete sucessful");
}
I can't explain why the above code doesn't work, but this would be good a replacement:
if let email = self.emailField?.text
{
if let password = self.passwordField?.text
{
//do smthg
}
}
Based on #Joel's answer, I've created a helper method.
func unwrap<T, U>(a:T?, b:U?, handler:((T, U) -> ())?) -> Bool {
switch (a, b) {
case let (.Some(a), .Some(b)):
if handler != nil {
handler!(a, b)
}
return true
default:
return false
}
}
// Usage
unwrap(a, b) {
println("\($0), \($1)")
}