2015-01-13 2 views
1

У меня есть этот Swift код, который компилируется просто отлично:Почему скобки вокруг «0x1000 - 1» вызывают ошибку времени компиляции?

let someArray = Array(count: 45, repeatedValue: 0) 
let a: UIntMax = 0x00010000 
let b = a + someArray.count 
let c = (b + 0x1000 - 1)/0x1000 
println("\(someArray.count == c), \(c)") 

Однако, я полагал, что переполняется будет чуть менее вероятно, если бы я убедился, что - 1 применяется к 0x1000 перед добавлением к b (на линии 4), поэтому я хотел бы изменить его на:

let c = (b + (0x1000 - 1))/0x1000 

Удивительно, но этот фрагмент кода не компилировать больше. Я получаю эту ошибку на println линии:

Не удалось найти участника convertFromStringInterpolationSegment

Что случилось? Почему мое выраженное в скобках выражение действует иначе, чем мой беспристрастный, и почему это влияет?

+0

Быстрое выражение типа иногда путается, это похоже на один из них. Я бы пошел и поместил билет в Apple. –

ответ

3

Очень странно. Добавление этих круглых скобок изменило тип вывода c от Int до UInt64. Это дает ошибку для последней строки, так как someArray.count - это Int, и вы не можете сравнивать разные типы.

Я бы (а) подал отчет об ошибке и (б) разделил выражения.


Посмотрел немного больше, теперь мне интересно, почему компилируется первая версия. Линия по линии:

  1. let a: UIntMax = 0x00010000

    a имеет тип UInt64. (UIntMax это просто тип псевдонима.)

  2. let b = a + someArray.count

    b также типа UInt64. «Но подождите, - говорите вы, - вы сказали, что не можете добавить UInt64 и Int экземпляров!» В этом случае оператор +, который используется эта одна:

    func +<T : Strideable>(lhs: T, rhs: T.Stride) -> T 
    

    UInt64 экземпляра в данном случае является strideable значения, с соответствующим экземпляром Int его Stride.

  3. let c = (b + 0x1000 - 1)/0x1000

    Глядя на подвыражения первых круглых скобках, ассоциативность + и - означает, что это эквивалентно ((b + 0x1000) - 1).+ оператор выбрал компилятор здесь является стандартной для UInt64, но оператор - это один, который принимает два Strideable значения и возвращает их Stride:

    func -<T : Strideable>(lhs: T, rhs: T) -> T.Stride 
    

    Это приводит к типу всего подвыражения быть Int вместо UInt64, поэтому c также является Int.

Я думаю, что ошибка компиляции происходит при выборе перегружать - оператора, так как нет никакой причины, чтобы не держать оценивать вещи, как UInt64.

+0

И если вы разделите назначение на 'let c1 = (b + 0x1000 - 1); пусть c2 = c1/0x1000', тогда 'c2' снова имеет тип' UInt64'. Таким образом, «плохой» выбор оператора '-' каким-то образом влияет на следующее разделение. –

+0

@MartinR Right - это некоторая комбинация вывода типа выражения и целочисленного литерального преобразования. –

+0

У меня есть еще одна хорошая для вас: для компиляции нужна точная структура 'b + constant - constant'. 'b + constant + constant' терпит неудачу,' b + constant' терпит неудачу. – zneak

0

Проблема возникает из-за того, что изменение выражения смущает вывод типа и приводит к тому, что c является UIntMax вместо Int (ошибочно IMO, я думаю, что он всегда должен быть UIntMax, но это другой вопрос). В частности, приведите результат, и вы «все будет в порядке:

let c = Int((b + (0x1000 - 1))/0x1000) 

Примечание:„Все будет хорошо“предполагает, что результат никогда не перетекает в Int, которая не доказуемо данный код вы показали.

+0

Встроенные целые конструкторы усекаются и битаут молча, они не ловушки при переполнении. – zneak

+0

Испытания на детской площадке утверждают, что вы ошибаетесь. 'let bar = 32000; let foo = UInt8 (bar); println (" \ (foo) ")' сбой. –

+0

Вы правы. Для этого вам нужно сделать 'UInt8 (truncatingBitPattern: ...)'. – zneak

Смежные вопросы