Casting CGFloat to Float en Swift

91

Necesito almacenar un valor como Float, pero los datos de origen son CGFloat:

let myFloat : Float = myRect.origin.x

pero esto da como resultado el error del compilador: 'NSNumber' no es del subtipo 'Float'

Entonces, si lo lanzo explícitamente así:

let myFloat : Float = myRect.origin.x as Float

pero esto a su vez da como resultado el error del compilador: 'No se puede convertir el tipo de expresión' Float 'a' Float ''

¿Cuál es la forma correcta de hacer esto y satisfacer al compilador, por favor?

Andrew Ebling
fuente
8
Tenga en cuenta que en sistemas de 64 bits, la conversión de CGFloat a Float pierde precisión: CGFloat es de 64 bits en sistemas de 64 bits y de 32 bits en sistemas de 32 bits, Float siempre es de 32 bits. Para evitar esto, puede usar Double en lugar de Float.
Lukas
Si profundiza en un CGFloat en Xcode y ve dónde está definido, verá que está definido como un flotante en una arquitectura de 32 bits y un doble en una arquitectura de 64 bits.
jcpennypincher

Respuestas:

173

Puedes usar el Float()inicializador:

let cgFloat: CGFloat = 3.14159
let someFloat = Float(cgFloat)
Erik
fuente
17
usar "float" como nombre de variable es algo confuso, ¿quizás el cambio sea algo como "swFloat"?
Pequeña estudiante de Fermat
2
"'flotar' es algo confuso". ¿Seriamente?
AlvinfromDiaspar
2
@AlvinfromDiaspar Sí, probablemente ya que otros idiomas usan en floatlugar de Float, por lo que parece ese tipo / palabra clave en lugar de un nombre de variable.
Supuhstar
29

Si eres tan vago como yo, en un Extensions.swift defina lo siguiente:

extension Int {
  var f: CGFloat { return CGFloat(self) }
}

extension Float {
  var f: CGFloat { return CGFloat(self) }
}

extension Double {
  var f: CGFloat { return CGFloat(self) }
}

extension CGFloat {
  var swf: Float { return Float(self) }
}

Entonces puedes hacer:

var someCGFloatFromFloat = 1.3.f
var someCGFloatFromInt = 2.f
var someFloatFromCGFloat = someCGFloatFromFloat.swf
hyouuu
fuente
1
parece un candidato para estructura genérica
μολὼν.λαβέ
@Ian, no entiendo tu pregunta ... ¿un ejemplo?
hyouuu
13

Por lo general, la mejor solución es mantener el tipo y el uso CGFloat, incluso en Swift. Eso es porque CGFloattiene un tamaño diferente en máquinas de 32 bits y 64 bits.

La palabra clave solo asse puede utilizar para la conversión dinámica (para subclases), por ejemplo

class A {
}

class B : A {
}

var a: A = B()
var b: B = a as B

Sin embargo, Double, Int, Floatetc no son subclases de uno al otro, por lo tanto, a "fundido" tiene que crear una nueva instancia, por ejemplo,

var d: Double = 2.0
var f: Float = Float(d) //this is an initialiser call, not a cast
var i: Int = Int(d) //this is an initialiser call, not a cast
Sulthan
fuente
Tenga en cuenta que también puede utilizar aspara convertir un tipo genérico en un tipo concreto. Por ejemplo, si tenía una función que acepta un tipo genérico que se ajusta a BinaryInteger, puede convertirlo en Intusando as?o as!.
Peter Schorn