【问题标题】:Does Swift support implicit conversion?Swift 是否支持隐式转换?
【发布时间】:2014-08-30 00:19:38
【问题描述】:

例如,我有以下代码:

    let numberOfBlocks = 3
    let blockWidth = SKSpriteNode(imageNamed: "image.png").size.width
    let padding = 20.0

    let offsetX : Float = (self.frame.size.width - (blockWidth * numberOfBlocks + padding * (numberOfBlocks-1))) / 2

我得到了错误:

'Double' 不能转换为 'UInt8'

有没有办法隐式转换数据类型(可能只针对原始数据类型)?

编辑:

我知道如何使用Iducool 建议的特定类型的构造函数进行显式转换。但这对我的问题没有太大帮助,因为我们甚至不知道在哪里添加转换。我在操场上简化了我的表达:

问题出在“padding”变量中,错误信息是

'Double' 不能转换为 'UInt8'。

所以我做了转换:

那么问题出在“blockWidth”变量中。

我再次添加了转换:

错误信息是:

类型“UInt8”不符合协议“FloatLiteralCovertible”

最终的工作表达式是:

简单快捷吗?我不这么认为。

【问题讨论】:

  • Apple 非常明确地表示 Swift 中没有隐式类型转换,并且也相当公开和明确地说明了原因。消除隐式类型转换至少可以消除一类常见(并且可能难以找到)的错误。
  • @David Swift Foundation 框架中有很多隐式类型转换。例如Array/NSArray, Int/NSNumber.
  • 至少在 Array/NSArray 的情况下它们没有被转换,它们被桥接。一个数组就是一个 NSArray,它有一个 isa 插槽和一切。发生的其他基金会桥接也是如此。即便如此,在大多数情况下,您最终还是不得不显式地转换它以使其有用。在 Int/NSNumber 的情况下,它只在非常特定的语义情况下完成,并且与 Swift 的许多丑陋一样,是因为试图保持 Objective-C 兼容性。从很多方面来看,他们似乎拥有一门非常干净的语言,然后决定将 Objective-C 兼容性移植到它上面。
  • 我编辑了这个问题,从标题和正文中删除了高度主观的语言 - 问题本身很好,但我建议不要使用看似具有挑衅性的措辞。
  • 我喜欢swift,因为它的语法简洁明了,这样我就可以为复杂的情况编写优雅的代码。但是对于这样一个简单的案例,Swift 让它变得如此困难。我并不是说隐式转换适用于所有情况。但是,如果它至少支持原始数据类型的隐式转换,它将使程序员的生活更轻松。

标签: ios swift implicit-conversion primitive-types


【解决方案1】:

可以进行隐式转换,但只能使用文字,并且可以从框中获得一些转换,例如Int -> Double:

let a = 3 // Int
let b = 100.5 // Double

// Doesn't work with variables
let c = a * b // Error: Binary operator '*' cannot be applied to operands of type 'Int' and 'Double'

// But this works, because Int(3) literal converts to Double(3.0) implicitly
let d = 3 * b // 301.5

如果你想进行反向转换Double -> Int 你应该用ExpressibleByFloatLiteral扩展Int

extension Int: ExpressibleByFloatLiteral {
    public init(floatLiteral value: Double) {
        self.init(value)
    }
}

// Double(100.5) converts to Int(100)
let e = a * 100.5 // 300

甚至可以从文字隐式转换为任何类型,例如String -> URLRequest

extension URLRequest: ExpressibleByStringLiteral {
    public init(stringLiteral value: String) {
        self.init(url: URL(string: value)!)
    }
}

let request: URLRequest = "https://www.google.com"

【讨论】:

    【解决方案2】:

    Swift 中没有隐式转换。

    快速转换的简单方法是使用特定类型的构造函数。

    如果你想从 double 中获取 Float,那么你可以使用 Float(doubleValue),同样如果你想将 float 转换为整数,那么你可以使用 Int(floatValue)

    在你的情况下:

    let intValue = UInt8(doubleValue)
    

    请注意,您将丢失小数点后的任何值。所以,选择更好的方法。以上转换只是为了帮助您理解。

    请注意,Swift 在推断浮点数的类型时总是选择 Double(而不是 Float)。

    【讨论】:

    • 最后一句是非常重要的提示,所以我在SpriteKit中通常使用Double作为数据类型来简化转换。顺便说一句,CGFloat 是 Double 而不是 Float。
    【解决方案3】:

    Swift 在 Xcode6 GM 中不再支持隐式转换。以下答案仅适用于 Xcode6 测试版。


    我不想谈论隐式转换的好坏,但如果你真的想要__conversion(),你可以拥有它

    例如如果您需要UInt8Int 可以从Double 转换

    extension Double {
        func __conversion() -> UInt8 { return UInt8(self) }
        func __conversion() -> Int { return Int(self) }
        // add more if you need to
    }
    

    xcrun swift
    Welcome to Swift!  Type :help for assistance.
      1> extension Double {
      2.     func __conversion() -> UInt8 { return UInt8(self) }
      3. }
      4> var d = 1.0
    d: Double = 1
      5> var u8 : UInt8 = d
    u8: UInt8 = 1
      6>
    

    注意:我不会把它放在我的生产代码中。我只想尽可能指出,但不推荐。

    【讨论】:

    • 很棒的发现,但我敢打赌这在 Swift 1.0 中是不可能的(或者如果是的话,它可能会,但使用的 API 不那么私密)。不过,我希望能够做到;非常小心和适度使用时,这是一项强大的功能。
    【解决方案4】:

    使用 bridgeToObjectiveC() 方法,您可以调用 Objective-C 中提供的方法,例如从一种原始数据类型转换为另一种数据类型

    variable_name.bridgeToObjectiveC().intValue
    

    会将名为 variable_name 的变量转换为整数

    【讨论】:

    • 至少感谢您不建议转换为字符串并返回。
    • 问题是关于表达式中的隐式转换,例如从DoubleInt。您的答案仅与此相关 - 但在其他情况下可能有用;)
    猜你喜欢
    • 2022-01-18
    • 2016-01-12
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多