Унарный оператор Swift с неявно развернутым необязательным

Поэтому я задал этот вопрос, и похоже, что причина

var num:Int! = 0
num++

не работает, потому что оператор ++ принимает параметр inout, который не является неявно развернутым необязательным параметром. Однако в

var num:Int! = 0
num = num + 1

оператор + работает с неявно развернутым необязательным параметром, что означает, что бинарный оператор не требует параметра inout. Итак, мой вопрос: почему у унарных и бинарных операторов разные требования к параметрам? Мне кажется глупым использовать Int! только с бинарными операторами, но использовать Int со всем.


person Adam Evans    schedule 01.08.2015    source источник


Ответы (1)


почему унарные и бинарные операторы имеют разные требования к параметрам?

Ну, это не унарный и бинарный вопрос. Есть унарные операторы, которые работают с Int!. Например:

var i: Int! = 17
var j = -i

- — унарный оператор, и он работает. Вопрос возвращается к проблеме inout. Операторы префикса и постфикса ++ для Int не работают с Int!, поскольку переменная передается как inout (поскольку ++ не только возвращает значение, но и изменяет исходную переменную). inout требует точного соответствия типа.

Обратите внимание, что неявно развернутые опции по-прежнему являются необязательными.

var i: Int! = 17
var k = i    // k has the type Int!
var m = i!   // m has the type Int

Таким образом, передача неявно развернутого опционала в качестве переменной inout, для которой требуется необязательный тип, не работает, потому что переменные inout должны точно соответствовать ожидаемому типу, а Int и Int! — это два совершенно разных типа. Переменная должна быть либо явно развернута, либо вам нужно предоставить перегруженную функцию, которая принимает необязательный тип.

Вы можете спросить, почему Swift просто не разворачивает Int! для вас и не вызывает ++ с Int? Ну, ++ и изменяет переменную, и возвращает значение. Если бы Swift развернул Int! и вызвал ++ с Int, то тип возврата был бы Int. Тогда у вас будут люди на StackOverflow, которые будут спрашивать: «Почему var i: Int! = 17; var j = i++ делает j Int вместо Int!?». Чтобы сделать это правильно, ++ должно возвращать Int, когда ему дается Int, и возвращать Int!, когда ему дается Int!. Итак, что нужно в перегруженной функции.

Можно перегрузить ++ и сделать префиксные и постфиксные функции ++ для Int!:

prefix func ++(inout x: Int!) -> Int! {
    return ++x!
}

postfix func ++(inout x: Int!) -> Int! {
    return x!++
}

var i: Int! = 17
var j = ++i
print("i = \(i), j = \(j)")  // "i = 18, j = 18"
j = i++
print("i = \(i), j = \(j)")  // "i = 19, j = 18"

Что касается того, почему дизайнеры Swift этого не сделали, только они знают, почему.

person vacawama    schedule 01.08.2015
comment
x++ намного быстрее, чем x = x + 1, возможно, поэтому они не реализовали его так, как вы указали. Также x!++ работает вместо x++, мне просто интересно, почему язык не автоматически разворачивает необязательный для вас, когда переменная неявно разворачивается. - person Adam Evans; 01.08.2015
comment
Они могут реализовывать, как хотят. Я просто хотел показать, что можно избавиться от мысли, что это невозможно. - person vacawama; 01.08.2015
comment
Там избавились от x = x + 1, который все равно не возвращал правильный результат для постфикса. - person vacawama; 01.08.2015
comment
Тип переменной inout должен точно совпадать. Int! и Int - два очень разных типа. Если бы они хотели поддерживать ++ с Int!, они, вероятно, сделали бы что-то вроде того, что я определил выше. - person vacawama; 01.08.2015
comment
Но зачем им вообще нужно ключевое слово inout, если оно делает его таким ограничительным? Разве они не могут просто сделать что-то вроде postfix func ++(x:Int) -> Int {return x++} и сделать так, чтобы распаковка происходила при передаче параметра и все работало? - person Adam Evans; 01.08.2015
comment
Вам нужно inout, потому что функция ++ не только возвращает значение, но и изменяет исходную переменную. - person vacawama; 01.08.2015
comment
Обратите внимание, что var i: Int! = 17; var j = -i работает, а - является унарным оператором. Некоторые унарные операторы работают с неявно развернутыми опциями. В этом случае - не изменяет исходную переменную, поэтому inout не требуется. - person vacawama; 01.08.2015