Swift是否支持隐式转换?

34

例如,我有以下代码:

    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建议的那样。但是对于我的问题来说,这并没有太大帮助,因为我们甚至不知道在哪里添加转换。我在 playground 中简化了表达式:

enter image description here

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

'Double' 无法转换为 'UInt8'

所以我进行了转换:

enter image description here

现在问题出现在“blockWidth”变量中。

我再次添加了转换:

enter image description here

然后错误消息是:

类型 'UInt8' 不符合协议 'FloatLiteralCovertible'

最终的工作表达式是:

enter image description here

是否简单而迅速?我认为不是。


4
Apple非常明确表示Swift中没有隐式类型转换,而且已经公开并明确解释了为什么这样做。消除隐式类型转换可以消除至少一种常见(并且可能难以找到)的错误类型。 - David Berry
2
@David,Swift Foundation 框架中有许多隐式类型转换。例如:Array/NSArrayInt/NSNumber - Bryan Chen
3
至少在数组/NSArray的情况下,它们并没有被转换,而是被桥接。一个Array就是一个NSArray,它拥有一个isa slot和所有其他东西。其他Foundation桥接也是一样的。即使在大多数情况下,你最终还是需要显式地进行强制类型转换才能使用它。对于Int/NSNumber,只在非常特定的语义情况下才会这样做,并且像Swift中许多难以看懂的部分一样,这是由于试图保持Objective-C兼容性。在许多方面,它看起来像他们本来有一个漂亮干净的语言,然后决定将Objective-C兼容性嫁接进去。 - David Berry
2
我编辑了这个问题,从标题和正文中删除了高度主观的语言 - 问题本身很好,但我建议避免使用看起来具有挑衅性的措辞。 - jtbandes
2
Swift的理念并不是让程序员通过编写可能存在问题的代码来简化他们的生活,而是通过强制编写绝对正确的代码来简化生活。 - gnasher729
显示剩余5条评论
4个回答

37

Swift 中没有隐式类型转换。

在 Swift 中进行类型转换的简单方法是使用特定类型的构造函数。例如,如果您想从 Double 转换为 Float,则可以使用 Float(doubleValue),同样地,如果您想将 Float 转换为整数,则可以使用 Int(floatValue)

针对您的情况:

let intValue = UInt8(doubleValue)

请注意,小数点后面的任何值都将丢失。因此,请选择更好的方式。上述转换仅是为帮助您理解而提供的。

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


3
最后一句话是非常重要的提示,因此我通常在SpriteKit中使用Double数据类型来简化转换。顺便提一下,CGFloat是Double而不是Float。 - Bagusflyer
你可以通过使用“ExpressibleBy...Literal”协议(例如ExpressibleByStringLiteral)来实现你的目标。有关更多信息,请参见此答案 - Senseful

26

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


我不想讨论隐式转换的好坏,但是你可以使用__conversion()实现它。

例如,如果你需要从DoubleUInt8Int进行转换:

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>

注意:我不会在我的生产代码中使用这个。我只是想尽可能指出它,但并不推荐使用它。

2
很好的发现,但我敢打赌这在Swift 1.0中不可能实现(如果可以,可能会使用较少的私有API)。虽然如此,我仍然希望能够做到;当小心谨慎地使用时,这是一个非常强大的功能。 - Form
虽然这不完全是隐式转换,但你可能可以使用类似ExpressibleByIntegerLiteral的东西来解决问题。更多信息请参见此答案 - Senseful

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

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


8
感谢您没有建议将其转换为字符串再转回来。 - hamstergene
1
问题是关于表达式中的隐式转换,例如从 Double 转换为 Int。您的回答只是间接相关 - 但在其他情况下可能会有用 ;) - CouchDeveloper

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"

还有其他类似的类型,例如用于字典数组 - Senseful

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接