2014-06-09 12 views
10

Cercando di fare l'aritmetica in una funzione che restituisce `CGFloat, ottengo un errore:confusione a causa di Swift manca la conversione implicita di CGFloat

Couldn't find overload for '/' that accepts supplied arguments

func kDCControlDegreesToRadians(x : CGFloat) -> CGFloat 
{ 
    return (M_PI * (x)/180.0) // error is here. 
} 

Qualcun altro ha visto questo tipo di problema?

+4

Questo non è un duplicato. Mentre l'errore lanciato è lo stesso, il motivo sottostante qui è molto più sfumato di un fraintendimento di tipo sicurezza e tipo di inferenza. – Cezar

+0

@Mani, ti suggerisco di provare a inventare un titolo diverso per la tua domanda. Così com'è, provoca confusione con il presunto duplicato e potrebbe far chiudere la tua domanda da persone che votano solo in base al titolo. – Cezar

+0

@Cezar Ho modificato il mio titolo, se ritieni che questo titolo faccia confusione, sentiti libero di modificare il mio titolo. – Mani

risposta

15

Questo è un problema con la conversione da double a float.

Su una macchina a 64 bit, CGFloat è definita come double e si compilerà senza problemi perché M_PI e x sono entrambe doppie.

Su una macchina a 32 bit, CGFloat è un float ma M_PI è ancora un doppio. Purtroppo, non ci sono cast impliciti a Swift, in modo da avere per lanciare in modo esplicito:

return (CGFloat(M_PI) * (x)/180.0) 

Il tipo per 180.0 letterale è dedotto.

In Swift 3

M_PI è deprecato, utilizzare CGFloat.pi invece:

return (x * .pi/180.0) 
+0

Spiega perché non ho alcun problema con questo codice. – Cezar

+0

Ancora la mia mente scorre con C e Objective-C, questo è un problema. Ti ho preso. Funzionando bene. Grazie @Sulthan .. – Mani

0

Questo dovrebbe risolvere l'errore:

func kDCControlDegreesToRadians(x : CGFloat) -> CGFloat 
{ 
    return (CGFloat(M_PI) * (x)/180.0) 
} 

Il motivo si verifica l'errore è dovuto al fatto x è esplicitamente dichiarato di essere un CGFloat, mentre M_PI ha il tipo CDouble, come si vede nella dichiarazione:

var M_PI: CDouble { get } /* pi    */ 

a causa di questo, è necessario lanciare M_PI digitare CGFloat in modo che corrisponda al tipo di x (come ho fatto in t codice sopra). In questo modo, non c'è conflitto nell'operare su tipi diversi.

nota che, contrariamente a quanto affermato in altre risposte (e come @Cezar commentato), non c'è bisogno di lanciare esplicitamente 180.0 al CGFloat tipo, perché è un letteralmente, e non ha un tipo esplicito, quindi verrà automaticamente convertito in CGFloat senza bisogno di un cast manuale.

+0

Dovrebbe esserci almeno un flag del compilatore per disabilitare questo tipo nazista. Uccide davvero la produttività – pkuhar

+0

Esiste, si chiama '-x obiettivo-c' – Greg

+0

@PartialyFinite che ha un diverso tipo di produttività ki]]. – pkuhar

11

In questo caso specifico ho un trucco carino per raccomandare

let π = CGFloat(M_PI)

Unicode in tutto il mondo e π è facile da ottenere con Opt + P

+0

+1 per un uso di nomi di simboli unicode che non mi spaventano tanto quanto la maggior parte do: D (mi chiedo se è possibile aggiungerlo come estensione, dato che 'CGFloat.π' lo renderebbe evidente che tipo di valore è ...) –

1

Il suo meglio per astrarre la complessità.In primo luogo creare un'estensione

extension Double { 
    /** Converts the specified value in degrees into radians. */ 
    func degrees() -> CGFloat { 
     return CGFloat(self) * CGFloat(M_PI/180.0) 
    } 
} 

poi usarlo nel codice come il seguente esempio

let angle = 30.0.degrees() 
let transform = CGAffineTransformRotate(self.sliderControl.transform, angle); 

All'inizio ero riluttante a estendere il doppio, perché non mi piace la creazione di un uso su misura personalizzato del linguaggio (dagli orrori di codifica trovati in C++). Tuttavia, l'esperienza pratica ha dimostrato che questo è un modo di astrazione naturale per il linguaggio.

Problemi correlati