Swift-爲何String轉換Int的結果是nil

摘要git

知其然,更要知其因此然。前段時間用 String 轉換 Int 處理時,發現一種狀況返回 nil,就換成 String 轉換 Double 的方式處理。今天就要來看看這種返回 nil 的狀況是怎麼形成的。swift

當有小數的 String 文本轉換爲 Int 類型時,返回的值並非我們想要的向下取整後的整數,而是 nil。less

// Int 轉換爲 String
let intStr = "2.78"
let int = Int(intStr) // nil

爲何是nil?今天就來解解這個疑惑。this

String 轉換 Int 本質

首先com+鼠標左鍵彈出選項,選擇jump to Definition(跳轉到定義)一波操做,來到 Int 的定義地方,直接全局搜索一下 String,直接看下定義。spa

/// 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)

出處找到了,不想費力看註釋的,直接看我給的結論:code

String 轉換爲 Int 類型,傳入 Int 的 description 參數,必須是一個或者多個0-9組合的整數,整數前能夠加「+」或者「-」。通俗說,這個 text 文本必須是一個整數。不然都返回 nil。orm

看到如今,大體能夠明白了Int("2.78")爲何是 nil。ip

String 轉換 Double 本質

看完String 轉換 Double 本質後,順勢也看下String 轉換 Double 本質。一樣的查找邏輯一波操做,找到它的定義ssl

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
    ///
    /// 此處省略 57 行註釋------------------
    ///
    /// - 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)
}

Double(string)中的 string 文本能夠是一個10進制、16進制或者浮點數的(這個很是關鍵)。也能夠添加「+」,「-」符號。ci

這裏簡單總結一下,Double 轉換爲 text,並保留幾位小數的處理方法,加深一些印象

let double = Double(2.7895)
// double 轉換爲 String
print("\(double)") // 輸出 "2.7895"

// 保留兩位小數
print(String(format:"%.2f", double) // 輸出 "2.79"

Int("2.78") 怎麼處理,不是 nil?

看完了上面兩個轉換的定義以後,那麼是否能夠組合一下,解決可能出現的 nil?那是固然。

首先將文本轉換爲 Double,而後將 Double 轉換爲 Int

Int(Double("2.78")!) // 2

Double 轉換 Int

代碼驗證沒有問題,那麼就看看,Double 轉換 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)

定義中能夠看到,Double 類型的數據,通過 Int 轉換後,會生成一個只保留整數的數(小數部分略去)。因此也就支持了上節部分的處理方式。

Double 類型整數省略 .000

在看 Double 轉換 Int定義時,無心間發現一個好玩的定義,先上定義

/// 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)

定義說明,能夠將一個精確標示的浮點數轉換爲 Int 類型。這裏的精確標示就是沒有小數的值。有了這個定義,那麼豈不是能夠解決某一個應用場景了嗎?

顯示存在須要保留2位小數的文本時,當浮點數是一個沒有小數的數值,那麼就顯示整數。

// 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
}

題外話

感謝看到這裏,感受有一點收穫,給個小贊。有分析的不到位,評論區留言幫我梳理。

偶爾有一些想要搞清楚的問題,評論區告訴我,我們一塊兒解決。

相關文章
相關標籤/搜索