Swift-为什么String转换Int的结果是nil

摘要

知其然,更要知其所以然。前段时间用 String 转换 Int 处理时,发现一种情况返回 nil,就换成 String 转换 Double 的方式处理。今天就要来看看这种返回 nil 的情况是怎么造成的。

当有小数的 String 文本转换为 Int 类型时,返回的值并不是咱们想要的向下取整后的整数,而是 nil。

// Int 转换为 String
let intStr = "2.78"
let int = Int(intStr) // nil

为什么是nil?今天就来解解这个疑惑。

String 转换 Int 本质

首先com+鼠标左键弹出选项,选择jump to DeFinition(跳转到定义)一波操作,来到 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)

出处找到了,不想费力看注释的,直接看我给的结论:

String 转换为 Int 类型,传入 Int 的 description 参数,必须是一个或者多个0-9组合的整数,整数前可以加“+”或者“-”。通俗说,这个 text 文本必须是一个整数。否则都返回 nil。

看到现在,大致可以明白了Int("2.78")为什么是 nil。

String 转换 Double 本质

看完String 转换 Double 本质后,顺势也看下String 转换 Double 本质。同样的查找逻辑一波操作,找到它的定义

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进制或者浮点数的(这个非常关键)。也可以添加“+”,“-”符号。

这里简单总结一下,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
}

题外话

感谢看到这里,感觉有一点收获,给个小赞。有分析的不到位,评论区留言帮我梳理。

偶尔有一些想要搞清楚的问题,评论区告诉我,咱们一起解决

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...