An optional value

The sentries value

  • C code

    int ch;
    while((ch = getchar()) ! = EOF) {printf("Read character %c\n", ch);
    } 
    printf("Reached end-of-file\n");
    Copy the code
  • C + + code

    auto vec = {1.2.3};
    auto iterator = std::find(vec.begin(),vec.end(),someValue);
    if(iterator ! = vec.end()) {
      std::cout << "vec contains" << *iterator << std:endl;
    }
    Copy the code
  • Java code

    int i = Integer.getInteger("123")
    Copy the code
  • Objective-C

    [[NSString alloc] initWithContentsOfURL: url encodig: NSUTF8StringEncoding error: &error];
    Copy the code

In all of the examples above, the functions return a “magic” number to indicate that no real value is returned. Such values are called sentinel values.

Solve the magic number problem by enumeration

  • Most languages support some form of enumerated type, which is a safer way to express all the values that a type might contain. Optional is also implemented through enumeration

    enum Optional<Wrapped> {
      case none
      case some(wrapped)
    }
    Copy the code

An overview of alternative values

  • Many of the optional values in Swift come from the language’s built-in support

if let

  • The **if let ** statement checks if the optional value is nil, and unpacks the optional value if it is not.

while let

  • The while let statement is very similar to an if let in that it terminates the loop when a condition returns nil.

Double optional value

  • The wrapper type of an optional value is also an optional value case, which results in nesting of optional values.

  • Case-based pattern matching allows us to apply the same rules to if, for, and while that we use for switch matching. The most useful scenario is the combination of optional values.

if var and while var

  • In addition to let, you can use var to match if, while, and for. This allows you to change variables within a statement block:

    let number = "1"
    if var i = Int(number) {
      i + = 1
      print(i)
    } / / 2
    Copy the code

Scope of optional values after unpacking

  • guard let

  • Never is also known as an uninhabited type. This type has no valid value and therefore cannot be built. In a generic environment, it is useful to combine Never and Result. For example, for A generic API that accepts Result

    (both A and E are generic arguments), you can pass in A Result<… , Never> means that the result will Never contain the failure case, because such a case cannot be built.
    ,>

  • In Swift, unattended types are implemented with an enum that does not contain any members:

    public enum Never {}
    Copy the code
  • Swift is very rigorous in distinguishing between the various “none” types. In addition to nil and Never, there is also Void, which is another way of writing a tuple:

    public typealias Void =(a)Copy the code

    Swift makes a careful distinction between “something that doesn’t exist” (nil), “something that exists and is empty” (Void), and “something that can’t happen” (Never).

  • The Guard is an explicit model that implies that we “continue only if the conditions hold.” The Swift compiler also checks to see if you have exited the current scope in the Guard block, and if not, you get a compilation error. Since compiler help is available, choose to use Guard whenever possible, even if it works fine.

Optional chain

  • In Objective-C, nothing happens when you send a message to nil. In Swift we achieve the same effect by “optional chaining” :

    delegate?.callback()
    Copy the code

Nil merge operator

  • And the | | operator,??The operator uses short circuiting to evaluate. When we usel ?? r, only iflWhen is nil,rIs going to be evaluated. This is because @Autoclosure is used as the second argument in the function declaration of the operator

Use optional values in string interpolation

  • Swift?? Operator does not support operations with type mismatches on both sides. Just for the special purpose of using optional values in string interpolation, add a?? The operators are also simple

    infix operator ?????: NilCoalescingPrecedence
    public func ????? <T>(optional: T? , defaultValue:@autoclouse() - >String) - >String {
      switch optional {
        case let value?:return String(describing: value)
        case nil: return defaultValue()
      }
    }
    Copy the code

Optional value map

  • Optional.mapIt’s very similar to the map method used in arrays and other sequences. But unlike operating on a series of values in a sequence, optional valuesmapOnly one value is operated on, and that is the possible value in the optional value. You can think of the optional value as a set of zero or one values, somapEither it doesn’t do anything with zero values, or it converts them when it does.

Flatmap optional values

let stringNumbers = ["1"."2"."3"."foo"]
let x = stringNumbers.first.map { Int($0)}// Optional(Optional(1))
Copy the code

FlatMap flattens the result into a single optional value. So y is going to be of type Int, right? :

let y = stringNumbers.first.flatMap { Int($0)}// Optional(1)
Copy the code

Use compactMap to filter nil

  • CompactMap – a map that filters out those nil values and unpacks non-nil values.

Optional value judgment, etc

  • When we use a non-optional value, Swift will always “upgrade” it to an optional value if we need to match it to an optional value type.

Optional value comparison

  • Now, if you want to do anything other than equality between the optional values, you need to unpack them first, and then explicitly indicate what to do with nil.

Timing of forced unpacking

You can use an exclamation point when you’re sure that something you have can’t possibly be nil, and you want the program to just die if it’s accidentally nil.

Improved error messages for forced unpacking

  • Add a!!!!! Operator, which combines forced unpacking with a more descriptive error message that will also be printed when the program exits unexpectedly:

    infix operator !!!!!
    
    func !!!!! <T>(wrapped: T? ,failureText:@autoclouse() - >String) - >T {
      if let x = wrapped { return x }
      fatalError(failureText())
    }
    Copy the code
    let s = "foo"
    let i = Int(s) !!!!! "Expecting integer, got \"\(s)\""
    Copy the code

Assertions are made in the debug release

  • Implement an exclamation point! ? Operator — Define this operator to assert failed unpacks and replace the value with the default in releases where the assertion does not trigger:

    infix operator ! ?
    
    func ! ? <T: ExpressibleByIntegerLiteral> 
    	(warpped: T? , failureText:@autoclouse() - >String) - >T
    {
      assert(wrapped ! = nil, failureText())
      return wrapped ?? 0
    }
    Copy the code

    Now, the following code will trigger the assertion at debug time, but print 0 in the release:

    let s = "20" 
    let i = Int(s) ! ? "Expecting integer, got \"\(s)\""
    Copy the code
  • There are three ways to suspend an operation. First, fatalError will accept a message and unconditionally stop the operation. The second option is to use assert to check the condition, and when the condition results in false, stop execution and output information. In a release, the assert is removed, which means the condition is not detected and the operation is never suspended. The third way is to use precondition, which has the same interface as assert but is not removed in the release, that is, execution is stopped as long as the condition is determined to be false.

Implicit unpacking optional values

Why use implicit optional values?

Reason 1: For now, we might need to go into Objective-C and call code that doesn’t check for the return; Or you might call a C library that is not annotated for Swift.

Reason 2: Because a value is nil only briefly, after a certain period of time, it is never nil again. The most common situation is two-phase initialization.

Implicit optional value behavior

While implicitly unpacked optional values behave like non-optional values, you can still use optional chains, nil merge, if let, map or compare them to nil, all of which are the same:

var s: String! = "Hello"
s?.isEmpty // Optional(false)
if let s = s { print(s) } // Hello
s = nil
s ?? "Goodbye" // Goodbye
Copy the code