Путаница из-за Swift, лишенная неявной конверсии CGFloat

Попытка выполнить арифметику в функции, которая возвращает `CGFloat, я получаю сообщение об ошибке:

Не удалось найти перегрузку для '/', которая принимает предоставленные аргументы

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

Кто-нибудь еще видел этот тип проблемы?

Ответ 1

Это проблема преобразования double в float.

На 64-битной машине CGFloat определяется как double, и вы скомпилируете его без проблем, потому что M_PI и x оба являются удвоенными.

На 32-битной машине CGFloat является float, но M_PI по-прежнему является двойным. К сожалению, в Swift нет неявных отбросов, поэтому вы должны явно указывать:

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

Выводится тип литерала 180.0.

В Swift 3

M_PI устарел, используйте CGFloat.pi вместо:

return (x * .pi / 180.0)

Ответ 2

В этом конкретном случае у меня есть симпатичный трюк, чтобы рекомендовать

let π = CGFloat(M_PI)

Unicode везде, а π легко получить с помощью Opt + P

Ответ 3

Лучше всего абстрагироваться от сложности. Сначала создайте расширение

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

затем используйте его в своем коде, например, в следующем примере

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

Сначала я не хотел продлевать Double, потому что мне не нравится создавать пользовательское использование языка (от ужасов от кодирования, найденных на С++). Однако практический опыт показал, что это способ абстрагирования, естественный для языка.

Ответ 4

Это должно исправить ошибку:

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

Причина возникновения ошибки заключается в том, что x явно объявлен как CGFloat, а M_PI имеет тип CDouble, как видно из объявления:

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

Из-за этого вам нужно указать M_PI для ввода CGFloat, чтобы он соответствовал типу x (как я уже делал в приведенном выше коде). Таким образом, нет конфликтов при работе на разных типах.

Обратите внимание, что вопреки тому, что указано в других ответах (и, как прокомментировал @Cezar), вам не нужно явно использовать 180.0 для типа CGFloat, потому что это буквально, и не имеет явного типа, поэтому автоматически будет преобразован в CGFloat без необходимости ручной трансляции.