zoukankan      html  css  js  c++  java
  • 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
    }
    

    题外话

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

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

  • 相关阅读:
    c++中stl函数的使用
    java 中String类的常见方法和StringBuffer类的使用
    c++模板类和模板函数
    c++简单工厂类的设计模式
    Android自定义的button按钮
    c++基类与派生类之间的转换
    Unity和Android结合出现Unabled to convert class into dex format
    jz2240用tftp下载程序步骤
    解决jz2440不能ping同主机问题
    android中的事件传递机制
  • 原文地址:https://www.cnblogs.com/shsuper/p/15046427.html
Copyright © 2011-2022 走看看