Abstract

Know the how and even more, know the why. A while back, when I converted String to Int, I found a case that returned nil, so I converted String to Double. So today we’re going to see how this returns nil happens.

When a String with a decimal is converted to an Int, the value returned is not the rounded integer we want, but nil.

// Convert Int to String
let intStr = "2.78"
let int = Int(intStr) // nil
Copy the code

Why nil? Let’s answer that question today.

String converts Int essence

Jump to Definition jump to Definition jump to Definition jump to Definition jump to Definition jump to Definition

    /// Creates a new integer value from the given string.
    ///
    /// The string passed as `description` may begin with a plus or minus sign
    /// character (`+` or `-`), followed by one or more numeric digits (`0-9`).
    ///
    /// let x = Int("123")
    /// // x == 123
    ///
    /// If `description` is in an invalid format, or if the value it denotes in
    /// base 10 is not representable, the result is `nil`. For example, the
    /// following conversions result in `nil`:
    ///
    /// Int(" 100") // Includes whitespace
    /// Int("21-50") // Invalid format
    /// Int("ff6600") // Characters out of bounds
    /// Int("10000000000000000000000000") // Out of range
    ///
    /// - Parameter description: The ASCII representation of a number.
    @inlinable public init?(_ description: String)
Copy the code

The source is found, don’t want to bother to read the comments, directly read my conclusion:

A String is converted to an Int by passing the description argument to an Int. The description argument must be one or more integers ranging from 0 to 9 that can be preceded by “+” or “-“. Colloquially, the text must be an integer. Otherwise they all return nil.

Now, you can sort of see why Int(“2.78”) is nil.

String converts Double essence

After you’ve seen the String conversion to Double essence, let’s also look at the String conversion to Double essence. The same search logic wave operation finds its definition

extension Double : LosslessStringConvertible {

    /// Creates a new instance from the given string.
    ///
    /// The string passed as `text` can represent a real number in decimal or
    /// hexadecimal format or special floating-point values for infinity and NaN
    /// ("not a number").
    ///
    /// The given string may begin with a plus or minus sign character (`+` or
    /// `-`). The allowed formats for each of these representations is then as
    /// follows:
    ///
    /// - A *decimal value* contains the significand, a sequence of decimal
    /// digits that may include a decimal point.
    ///
    // let c = Double("-1.0")
    /// // c == -1.0
    ///
    // let d = Double("28.375")
    /// // d == 28.375
    ///
    /// Omit 57 lines of comment ------------------
    ///
    /// - Parameter text: The input string to convert to a `Double` instance. If
    /// `text` has invalid characters or is in an invalid format, the result
    /// is `nil`.
    @inlinable public init?<S> (_ text: S) where S : StringProtocol

    @available(macOS 11.0.iOS 14.0.watchOS 7.0.tvOS 14.0.*)
    public init?(_ text: Substring)
}
Copy the code

The string text in Double(string) can be a decimal, hexadecimal, or floating-point number (this is crucial). You can also add “+” and “-” symbols.

Here’s a quick summary of how to convert Double to text and keep a few decimal places, just to make some sense

Print (String(format:"%.2f", "%.2f", "%.2f", "%.2f"); Double) // output "2.79"Copy the code

What if Int(“2.78”) is not nil?

So now that we’ve seen the definition of these two transformations, can we combine them to solve for any nil that might occur? Of course.

First convert the text to Double, then Double to Int.

Int(Double("2.78")!) / / 2
Copy the code

Double conversion Int

So let’s see what happens when we convert Double to Int.


    /// Creates an integer from the given floating-point value, rounding toward
    /// zero.
    ///
    /// Any fractional part of the value passed as `source` is removed, rounding
    /// the value toward zero.
    ///
    /// let x = Int(21.5)
    /// // x == 21
    /// let y = Int(-21.5)
    /// // y == -21
    ///
    /// - Parameter source: A floating-point value to convert to an integer.
    /// `source` must be representable in this type after rounding toward
    /// zero.
    public init(_ source: Double)
Copy the code

As you can see from the definition, the conversion of a Double to an Int will result in an integer only number (with the decimal part omitted). So it supports the way we did in the last section.

Double integers omit.000

While looking at the Double to Int definition, I came across an interesting definition


    /// Creates an integer from the given floating-point value, if it can be
    /// represented exactly.
    ///
    /// If the value passed as `source` is not representable exactly, the result
    /// is `nil`. In the following example, the constant `x` is successfully
    /// Created from a value of '21.0' while the attempt to initialize the
    /// constant `y` from `21.5` fails:
    ///
    Let x = Int(exactly: 21.0)
    /// // x == Optional(21)
    // let y = Int(exactly: 21.5)
    /// // y == nil
    ///
    /// - Parameter source: A floating-point value to convert to an integer.
    public init?(exactly source: Double)
Copy the code

This definition states that you can convert a precisely identified floating point number to an Int. The exact notation here is that there is no decimal value. With this definition, isn’t it possible to solve a specific application scenario?

When there is text that needs to hold 2 decimal places, an integer is displayed when the floating point number is a number with no decimal.

// old
String(format: "%.2f".2.578) / / 2.58
String(format: "%.2f".2.0) / / 2.00

// new
if Int(exactly: 2.00) ! = nil {
    "\(Int(exactly: 2.00)!)" / / 2
}
Copy the code

digression

Thanks for seeing here, feel a little harvest, give a little praise. The analysis is not in place, comment area comments to help me comb.

Let me know in the comments section when I have some questions I’d like to figure out, and we’ll work them out together.