Подтвердить что ты не робот

Литье по типу Strange Swift

Я только что заметил, что Swift выполняет литье некоторых типов по Int и Double. Когда я пытаюсь оценить

(10 / 3.0) - (10 / 3)

0.333..., но на самом деле 0.0. Может кто-нибудь объяснить это, пожалуйста?

4b9b3361

Ответ 1

Да, я также нашел это довольно неожиданным. Double соответствует как FloatLiteralConvertible, так и IntegerLiteralConvertible (ExpressibleByFloatLiteral и ExpressibleByIntegerLiteral в Swift 3). Поэтому Double может быть инициализирован литералом с плавающей запятой

let a = 3.0

или с целым литералом:

let b : Double = 10

(То же самое верно для других типов с плавающей запятой, таких как Float и CGFloat.)

Теперь это может быть неожиданно для всех нас с фоном (Objective-) C что оба утверждения

let x : Double = 10/4     // x = 2.5 .  Really? Yes!
let y = 10/4 as Double    // Same here ...

присвойте переменной 0.25 переменной. Из контекста результат деление должно быть Double, а Swift не подразумевает конвертирование типов. Поэтому / должен быть оператором деления с плавающей запятой

func /(lhs: Double, rhs: Double) -> Double

поэтому компилятор создает оба аргумента как Double из литералов "10" и "4". (Если 10/4 рассматривались как деление двух целых чисел то результат также будет целым числом, и это не может быть назначено до Double.)

Обратите внимание, что это отличается от

let z = Double(10/4)   // z = 2.0 . (I just thought that I understood it &%$!?)

который выполняет целочисленное деление и преобразует результат в Double. Double имеет конструктор init(_ v: Int), поэтому 10/4 можно рассматривать как деление двух целых чисел.

Это выглядит немного странно, если мы суммируем эти результаты:

let x : Double = 10/4     // x = 2.5 
let y = 10/4 as Double    // y = 2.5
let z = Double(10/4)      // z = 2.0

Теперь мы можем применить эти результаты к вашему выражению

(10 / 3.0) - (10 / 3)

Первая часть (10 / 3.0) может быть только Double, поэтому - должен быть оператором вычитания с плавающей запятой

func -(lhs: Double, rhs: Double) -> Double

и, следовательно, (10 / 3) также должен быть Double. Опять же, / должен быть оператором деления с плавающей запятой, поэтому 10 и 3 рассматриваются как константы Double.

Поэтому выражение эквивалентно

(Double(10) / 3.0) - (Double(10) / Double(3))

и оценивается до 0.0. Если вы измените выражение на

(10 / 3.0) - Double(10 / 3)

то результат 0.333..., потому что в этом контексте 10 / 3 является разделение двух целых констант, как объяснялось выше.