2015-03-02 7 views
8

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

(10/3.0) - (10/3) 

0.333... ожидается, но на самом деле это 0.0. Не могли бы вы объяснить это?

ответ

12

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

let a = 3.0 

или с целочисленный литерал:

let b : Double = 10 

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

Теперь это может быть неожиданно для всех нас с (объективно-) 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 10 может рассматриваться как деление двух целых чисел здесь.

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

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 является деление двух целых констант, как описано выше.

+2

Отличное объяснение! –