摘要
知其然,更要知其所以然。前段時(shí)間用 String 轉(zhuǎn)換 Int 處理時(shí)仗扬,發(fā)現(xiàn)一種情況返回 nil,就換成 String 轉(zhuǎn)換 Double 的方式處理蕾额。今天就要來看看這種返回 nil 的情況是怎么造成的早芭。
當(dāng)有小數(shù)的 String 文本轉(zhuǎn)換為 Int 類型時(shí),返回的值并不是咱們想要的向下取整后的整數(shù)诅蝶,而是 nil退个。
// Int 轉(zhuǎn)換為 String
let intStr = "2.78"
let int = Int(intStr) // nil
為什么是nil?今天就來解解這個(gè)疑惑调炬。
String 轉(zhuǎn)換 Int 本質(zhì)
首先com+鼠標(biāo)左鍵
彈出選項(xiàng)语盈,選擇jump to Definition
(跳轉(zhuǎn)到定義)一波操作,來到 Int 的定義地方缰泡,直接全局搜索一下 String
刀荒,直接看下定義。
/// 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)
出處找到了棘钞,不想費(fèi)力看注釋的缠借,直接看我給的結(jié)論:
String 轉(zhuǎn)換為 Int 類型,傳入 Int 的 description 參數(shù)宜猜,必須是一個(gè)或者多個(gè)0-9組合的整數(shù)泼返,整數(shù)前可以加“+”或者“-”。通俗說宝恶,這個(gè) text 文本必須是一個(gè)整數(shù)符隙。否則都返回 nil。
看到現(xiàn)在垫毙,大致可以明白了Int("2.78")
為什么是 nil霹疫。
String 轉(zhuǎn)換 Double 本質(zhì)
看完String 轉(zhuǎn)換 Double 本質(zhì)后,順勢(shì)也看下String 轉(zhuǎn)換 Double 本質(zhì)综芥。同樣的查找邏輯一波操作丽蝎,找到它的定義
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 文本可以是一個(gè)10進(jìn)制、16進(jìn)制或者浮點(diǎn)數(shù)的數(shù)(這個(gè)非常關(guān)鍵)。也可以添加“+”屠阻,“-”符號(hào)红省。
這里簡(jiǎn)單總結(jié)一下,Double 轉(zhuǎn)換為 text国觉,并保留幾位小數(shù)的處理方法,加深一些印象
let double = Double(2.7895)
// double 轉(zhuǎn)換為 String
print("\(double)") // 輸出 "2.7895"
// 保留兩位小數(shù)
print(String(format:"%.2f", double) // 輸出 "2.79"
Int("2.78") 怎么處理吧恃,不是 nil?
看完了上面兩個(gè)轉(zhuǎn)換的定義之后麻诀,那么是否可以組合一下痕寓,解決可能出現(xiàn)的 nil?那是當(dāng)然蝇闭。
首先將文本轉(zhuǎn)換為 Double呻率,然后將 Double 轉(zhuǎn)換為 Int。
Int(Double("2.78")!) // 2
Double 轉(zhuǎn)換 Int
代碼驗(yàn)證沒有問題呻引,那么就看看礼仗,Double 轉(zhuǎn)換 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 類型的數(shù)據(jù)元践,經(jīng)過 Int 轉(zhuǎn)換后,會(huì)生成一個(gè)只保留整數(shù)的數(shù)(小數(shù)部分略去)蹂风。所以也就支持了上節(jié)部分的處理方式卢厂。
Double 類型整數(shù)省略 .000
在看 Double 轉(zhuǎn)換 Int定義時(shí),無意間發(fā)現(xiàn)一個(gè)好玩的定義惠啄,先上定義
/// 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)
定義說明慎恒,可以將一個(gè)精確標(biāo)示的浮點(diǎn)數(shù)轉(zhuǎn)換為 Int 類型。這里的精確標(biāo)示就是沒有小數(shù)的值撵渡。有了這個(gè)定義融柬,那么豈不是可以解決某一個(gè)應(yīng)用場(chǎng)景了嗎?
顯示存在需要保留2位小數(shù)的文本時(shí)趋距,當(dāng)浮點(diǎn)數(shù)是一個(gè)沒有小數(shù)的數(shù)值粒氧,那么就顯示整數(shù)。
// 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
}
題外話
感謝看到這里节腐,感覺有一點(diǎn)收獲外盯,給個(gè)小贊。有分析的不到位翼雀,評(píng)論區(qū)留言幫我梳理饱苟。
偶爾有一些想要搞清楚的問題,評(píng)論區(qū)告訴我狼渊,咱們一起解決箱熬。