Операторы «++» и «-» устарели Xcode 7.3


139

Я просматриваю заметки Xcode 7.3 и замечаю эту проблему.

Операторы ++ и - устарели

Может ли кто-нибудь объяснить, почему он устарел? И я прав, что в новой версии Xcode теперь вы собираетесь использовать вместо ++этого x += 1;

Пример:

for var index = 0; index < 3; index += 1 {
    print("index is \(index)")
}

Снимок экрана для предупреждения


6
Я думаю, что этот вопрос выходит за рамки stackoverflow в основном потому, что все принятые предложения по быстрой эволюции можно найти в Github, вы можете узнать больше о том, почему это предложение github.com/apple/swift-evolution/blob/master / предложения /…
Виктор Сиглер

7
Я серьезно подумываю вернуться к Objective-C. Не стоит пытаться угнаться за всеми изменениями в Swift.
Грег Браун

3
@OlegGordiichuk Это вещь для-петли , как C-стиль будет удален тоже увидеть эту github.com/Vkt0r/swift-evolution/blob/master/proposals/... , так что вам не нужно использовать больше ++и --операторов
Виктор Сиглер

10
На мой вкус, слишком много критических изменений. Я полностью за улучшения, но я действительно не хочу тратить свое время на переписывание значительной части моей кодовой базы каждый раз, когда выходит релиз Xcode.
Грег Браун

4
@Fogmeister Не знаю, как я могу быть яснее. Я бы предпочел использовать Swift, но мне кажется, что он недостаточно стабилен. В прошлом я много работал с другими языками и никогда не сталкивался с таким количеством критических изменений за такой короткий период времени. Я чувствую, что Apple хочет, чтобы мы все приняли Swift, но они делают это труднее, чем следовало бы.
Грег Браун

Ответы:


211

Полное объяснение здесь от Криса Lattner, создателя Свифта. Подытожу по пунктам:

  1. Это еще одна функция, которую вам нужно изучить при изучении Swift.
  2. Не намного короче, чем x += 1
  3. Swift - это не C.Не стоит переносить их только для того, чтобы угодить программистам на C.
  4. Его основное использование - это цикл for в стиле C:, у for i = 0; i < n; i++ { ... }которого Swift есть лучшие альтернативы, например for i in 0..<n { ... }(цикл for в стиле C также выходит )
  5. Может быть сложно читать и поддерживать, например, каково значение x - ++xили foo(++x, x++)?
  6. Крису Латтнеру это не нравится.

Для тех, кто заинтересован (и во избежание гниения ссылок), Латтнер своими словами приводит следующие доводы:

  1. Эти операторы увеличивают нагрузку на изучение Swift в качестве первого языка программирования - или в любом другом случае, когда вы еще не знаете эти операторы на другом языке.

  2. Их выразительное преимущество минимально - x ++ ненамного короче x + = 1.

  3. Swift уже отличается от C тем, что операции =, + = и другие операции, подобные присваиванию, возвращают Void (по ряду причин). Эти операторы несовместимы с этой моделью.

  4. Swift обладает мощными функциями, которые устраняют многие из распространенных причин, по которым вы бы использовали ++ i в цикле for в стиле C на других языках, поэтому они относительно редко используются в хорошо написанном коде Swift. Эти функции включают цикл for-in, диапазоны, перечисление, отображение и т. Д.

  5. Код, который фактически использует значение результата этих операторов, часто сбивает с толку и неуловим для читателя / разработчика кода. Они поощряют "чрезмерно хитрый" код, который может быть симпатичным, но трудным для понимания.

  6. Хотя Swift имеет четко определенный порядок оценки, любой код, зависящий от него (например, foo (++ a, a ++)), был бы нежелательным, даже если бы он был четко определен.

  7. Эти операторы применимы к относительно небольшому количеству типов: целочисленные скаляры и скаляры с плавающей запятой, а также концепции, подобные итераторам. Они не применяются к комплексным числам, матрицам и т. Д.

Наконец, они не соответствуют метрике «если бы у нас их еще не было, добавили бы мы их в Swift 3?»


54
Я думаю, настоящий ответ - номер 6. Это нормально, мы (бывшие программисты C, Java, ...) достаточно гибки :-). Как правило, для реального мира достаточно мутации, кроссовера и отбора. Я, ты и Крис тоже, мы все являемся результатом этих трех операторов ...
user3441734 02

5
Пункт 5: Они всегда зависели от реализации в C, и никто из здравомыслящих людей никогда их не делал. Просто определите поведение, и мы к нему привыкнем. Лучше, чем возвращаться и менять старый добрый код без всякой причины.
Echelon

3
Мне нравится пункт 3. Вы не можете быть прикованы к договору о наследстве вечно. Я люблю C, но вы создаете новый язык программирования; имеет смысл начать с настолько чистого листа, насколько вам нужно.
Николас Миари

8
Это потому, что яблоко любит заставлять вас думать так же, как они. Я думаю, что это прекрасно и используется везде, где вам нужно увеличивать или уменьшать переменную. Это не то, чему вам "нужно учиться", вы прекрасно справитесь без этого. А №5 - это просто плохо написанный код, подобного которому я никогда не видел. Итак, # 6 это так. Достаточно описать это, чтобы заставить меня почесать затылок и выполнить поиск в Google, так что спасибо, что потратил мое время, Крис.
csga5000

4
@ csga5000 Это довольно слабый аргумент, учитывая, что вы можете просто определить оператор самостоятельно, если действительно хотите. Это не имеет ничего общего с тем, что Apple хочет, чтобы люди думали, как они. Это просто не соответствует языку. Если ++бы в языках C-стиля не существовало, никто в здравом уме не взглянул бы на дизайн Swift 3.0 и не подумал бы, что ++оператор был бы хорошим дополнением к нему.
overactor 02

38

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

Я лично предпочитаю ++и --операторов. Не могу согласиться с мнением, что ими сложно или сложно управлять. Как только разработчик поймет, что делают эти операторы (а мы говорим о довольно простых вещах), код должен быть очень ясным.

В объяснении, почему операторы объявлены устаревшими, упоминается, что их основное использование было в C-стиле для циклов. Я не знаю, как другие, но я лично не использую циклы в стиле C, и есть еще много других мест или ситуаций, когда полезен оператор ++or --.

Я хотел бы также отметить , что varName++возвращает значение , поэтому он может быть использован в returnто время как varName += 1не может.

Для любого из вас, кто хотел бы, чтобы эти операторы работали, вот решение:

prefix operator ++ {}
postfix operator ++ {}

prefix operator -- {}
postfix operator -- {}


// Increment
prefix func ++(inout x: Int) -> Int {
    x += 1
    return x
}

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

prefix func ++(inout x: UInt) -> UInt {
    x += 1
    return x
}

postfix func ++(inout x: UInt) -> UInt {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Int8) -> Int8 {
    x += 1
    return x
}

postfix func ++(inout x: Int8) -> Int8 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt8) -> UInt8 {
    x += 1
    return x
}

postfix func ++(inout x: UInt8) -> UInt8 {
    x += 1
    return (x - 1)
}
prefix func ++(inout x: Int16) -> Int16 {
    x += 1
    return x
}

postfix func ++(inout x: Int16) -> Int16 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt16) -> UInt16 {
    x += 1
    return x
}

postfix func ++(inout x: UInt16) -> UInt16 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Int32) -> Int32 {
    x += 1
    return x
}

postfix func ++(inout x: Int32) -> Int32 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt32) -> UInt32 {
    x += 1
    return x
}

postfix func ++(inout x: UInt32) -> UInt32 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Int64) -> Int64 {
    x += 1
    return x
}

postfix func ++(inout x: Int64) -> Int64 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt64) -> UInt64 {
    x += 1
    return x
}

postfix func ++(inout x: UInt64) -> UInt64 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Double) -> Double {
    x += 1
    return x
}

postfix func ++(inout x: Double) -> Double {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Float) -> Float {
    x += 1
    return x
}

postfix func ++(inout x: Float) -> Float {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Float80) -> Float80 {
    x += 1
    return x
}

postfix func ++(inout x: Float80) -> Float80 {
    x += 1
    return (x - 1)
}

prefix func ++<T : _Incrementable>(inout i: T) -> T {
    i = i.successor()
    return i
}

postfix func ++<T : _Incrementable>(inout i: T) -> T {
    let y = i
    i = i.successor()
    return y
}

// Decrement
prefix func --(inout x: Int) -> Int {
    x -= 1
    return x
}

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

prefix func --(inout x: UInt) -> UInt {
    x -= 1
    return x
}

postfix func --(inout x: UInt) -> UInt {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Int8) -> Int8 {
    x -= 1
    return x
}

postfix func --(inout x: Int8) -> Int8 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt8) -> UInt8 {
    x -= 1
    return x
}

postfix func --(inout x: UInt8) -> UInt8 {
    x -= 1
    return (x + 1)
}
prefix func --(inout x: Int16) -> Int16 {
    x -= 1
    return x
}

postfix func --(inout x: Int16) -> Int16 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt16) -> UInt16 {
    x -= 1
    return x
}

postfix func --(inout x: UInt16) -> UInt16 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Int32) -> Int32 {
    x -= 1
    return x
}

postfix func --(inout x: Int32) -> Int32 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt32) -> UInt32 {
    x -= 1
    return x
}

postfix func --(inout x: UInt32) -> UInt32 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Int64) -> Int64 {
    x -= 1
    return x
}

postfix func --(inout x: Int64) -> Int64 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt64) -> UInt64 {
    x -= 1
    return x
}

postfix func --(inout x: UInt64) -> UInt64 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Double) -> Double {
    x -= 1
    return x
}

postfix func --(inout x: Double) -> Double {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Float) -> Float {
    x -= 1
    return x
}

postfix func --(inout x: Float) -> Float {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Float80) -> Float80 {
    x -= 1
    return x
}

postfix func --(inout x: Float80) -> Float80 {
    x -= 1
    return (x + 1)
}

prefix func --<T : BidirectionalIndexType>(inout i: T) -> T {
    i = i.predecessor()
    return i
}

postfix func --<T : BidirectionalIndexType>(inout i: T) -> T {
    let y = i
    i = i.predecessor()
    return y
}

Мне не нравятся ваши return (x - 1)операторы постфикса - ИМХО, лучше поддерживать семантику, которую они возвращают (копию) исходного значения, а не то, что вы получите, если это сделаетеx + 1 - 1
Альнитак

Мне это тоже не нравится, но я не знаю другого (лучшего, более чистого) способа сделать это. Я не совсем понимаю ваш второй момент.
0101

1
Понятно, я не хотел делать это только ради создания другой переменной (или, скорее, постоянной в данном случае). Если мы говорим Intтолько о том, что результат (x + 1)будет переполнен, что прервет выполнение и, следовательно result - 1, даже не будет запущено. Однако другие типы данных, такие как, Doubleнапример, ведут себя по-другому, поэтому мне нужно это исследовать.
0101

3
Вы тоже можете использовать deferдля этого. defer { x += 1 }; return x
Тим Вермёлен

4
почему бы не использовать дженерики и не написать это в несколько строк?
μολὼν.λαβέ

22

Apple удалила ++и упростила это другим старым традиционным способом.

Вместо этого ++вам нужно написать +=.

Пример:

var x = 1

//Increment
x += 1 //Means x = x + 1 

Аналогично для оператора декремента --нужно написать-=

Пример:

var x = 1

//Decrement
x -= 1 //Means x = x - 1

Для forпетель:

Пример приращения:

Вместо того

for var index = 0; index < 3; index ++ {
    print("index is \(index)")
}

Ты можешь написать:

//Example 1
for index in 0..<3 {
    print("index is \(index)")
}

//Example 2
for index in 0..<someArray.count {
    print("index is \(index)")
}

//Example 3
for index in 0...(someArray.count - 1) {
    print("index is \(index)")
}

Пример уменьшения:

for var index = 3; index >= 0; --index {
   print(index)
}

Ты можешь написать:

for index in 3.stride(to: 1, by: -1) {
   print(index)
}
//prints 3, 2

for index in 3.stride(through: 1, by: -1) {
   print(index)
}
//prints 3, 2, 1

for index in (0 ..< 3).reverse() {
   print(index)
}

for index in (0 ... 3).reverse() {
   print(index)
}

Надеюсь это поможет!


1
Они ничего не заменили; +=был там все время.
Николас Миари

@NicolasMiari Да, просто редактирую в гораздо лучшем формате
Сохил Р. Мемон

@NicolasMiari Не могли бы вы проверить сейчас?
Сохил Р. Мемон

3
А как насчет ++iи --i?
Zigii Wong

7

Крис Латтнер начал войну против ++ и -. Он пишет: «Код, который фактически использует значение результата этих операторов, часто сбивает с толку и неуловим для читателя / разработчика кода. Они поощряют «чрезмерно хитрый» код, который может показаться симпатичным, но трудным для понимания… .Хотя Swift имеет четко определенный порядок оценки, любой код, который зависит от него (например, foo (++ a, a ++)), был бы нежелательным, даже если бы он был четко определен ... они не соответствуют метрике «если бы у нас их еще не было, добавили бы мы их в Swift 3?» »

Apple хотела сохранить чистый, ясный, понятный, понятный и понятный язык. И поэтому они устарели ключевыми словами ++ и -.


9
Чистый? Посмотри на этот ад обратных вызовов и назови его чистым? Я не согласен ... И я бы добавил: оставьте ++ & - в покое
mcatach

22
что-то вроде ...for i in 0.stride(to: 10, by: 2)...или ...for i in (1...10).reverse()...чисто ?!
mad_manny 01

6
Согласен. Аргумент «чистоты» фундаментально противоречит остальной части Swift. Исходя из Objective-C, который объективно нечист, довольно сложно принять «чистый» как цель языка Apple.
Адриан Бартоломью

2
Попробуйте разобрать json и swift и скажите, насколько он чист.
nickthedude

6

Снимок экрана для предупреждения

Fix-it featureИз Xcode дает четкий ответ на этот вопрос.

Решение предупреждения

Заменить ++ increment operatorна старомодный value += 1(сокращенный оператор) и -- decrement operatorнаvalue -= 1


6

Для Swift 4, вы можете восстановить ++и --оператор в качестве расширений для Intи других типов. Вот пример:

extension Int{
   static prefix func ++(x: inout Int) -> Int {
        x += 1
        return x
    }

    static postfix func ++(x: inout  Int) -> Int {
        defer {x += 1}
        return x
    }

    static prefix func --(x: inout Int) -> Int {
        x -= 1
        return x
    }

    static postfix func --(x: inout Int) -> Int {
        defer {x -= 1}
        return x
    }
}

Он работает так же , как и для других типов, таких как UIInt, Int8, Float, Doubleи т.д.

Вы можете вставить эти расширения в один файл в корневой каталог, и они будут доступны для использования во всех других ваших файлах.

Я заметил несколько голосов против моего ответа здесь, почти сразу после того, как опубликовал его. Я воспринимаю это скорее как философское несогласие, чем критику того, как работает мой код. Он отлично работает, если посмотреть на детской площадке.

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

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

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

Я считаю, что синтаксических различий между языками должно быть ровно столько, сколько необходимо, и не более того.


Я люблю, когда языки «осмеливаются» отличаться. Честно говоря, существует слишком много языков с синтаксисом C, и C был разработан ДОЛГОЕ время назад ... языковой опыт был более 50 лет ... несмотря на это, поскольку этот ответ не стал тирадой по операторам, тем не менее голос за.
user2864740

5

Вот общая версия кода, опубликованного на данный момент. Я хотел бы выразить те же опасения, что и другие: лучше не использовать их в Swift. Я согласен, что это может сбить с толку тех, кто читает ваш код в будущем.

prefix operator ++
prefix operator --
prefix func ++<T: Numeric> (_ val: inout T) -> T {
    val += 1
    return val
}

prefix func --<T: Numeric> (_ val: inout T) -> T {
    val -= 1
    return val
}

postfix operator ++
postfix operator --
postfix func ++<T: Numeric> (_ val: inout T) -> T {
    defer { val += 1 }
    return val
}

postfix func --<T: Numeric> (_ val: inout T) -> T {
    defer { val -= 1 }
    return val
}

Это также можно записать как расширение числового типа.


Я добавил @discardableResultк каждой из этих функций, чтобы отключить предупреждение о неиспользовании возвращаемого значения; в остальном именно то, что я искал.
Девин Лейн

4

Из документов :

Операторы увеличения / уменьшения в Swift были добавлены на очень ранних этапах разработки Swift в качестве переноса из C. Они были добавлены без особого внимания, и с тех пор о них особо не задумывались. Этот документ позволяет по-новому взглянуть на них и, в конечном итоге, рекомендует полностью удалить их, поскольку они сбивают с толку и не несут на себе веса.


Другими словами, эта операция слишком дорогая для использования?
Олег Гордийчук 02

2
github.com/apple/swift-evolution/blob/master/proposals/… здесь вы можете прочитать об этом, но это не потому, что это дорого, а скорее из-за языкового дизайна.
Даниэль Надь

Итак, я, Андерсен Свифт, собираюсь отказаться от поддержки функций C-style
Олег Гордийчук

2
@OlegGordiichuk ну, я бы сказал, они хотят подчеркнуть, что Swift не является надмножеством C, в отличие от Objective-C.
Даниэль Надь

1
@mah, многое из того, что ты сказал, вообще не имеет смысла. Каким образом «не ориентированы на существующих разработчиков»? Точно так же, как Java не ориентирована на разработчиков PHP? «ориентированы на тех, кто может не иметь склонности быть разработчиками»? Да, потому что все эти не-разработчики откусывают руку от протокольно-ориентированного программирования и дженериков. «Способ обеспечения хорошего дизайна» просто взгляните на SO, вы увидите, что ни один язык программирования не может «обеспечить хороший дизайн».
Fogmeister

0
var value : Int = 1

func theOldElegantWay() -> Int{
return value++
}

func theNewFashionWay() -> Int{
let temp = value
value += 1
return temp
}

Это определенно недостаток, правда?


5
Вы имеете в виду элегантный, например, «вы должны запомнить все тонкости языка программирования C, иначе сразу не очевидно, вернет ли первый вызов 1 или 2»? Я думаю, мы все можем сэкономить несколько дополнительных строк кода в обмен на то, чтобы не потратить несколько минут, ломая голову, пытаясь найти причину ошибки с помощью глупой ошибки ...
Николас Миари

0

Поскольку вы никогда не работаете с указателями в Swift, на мой взгляд, имеет смысл удалить операторы ++и --. Однако, если вы не можете жить без него, вы можете добавить в свой проект следующие объявления операторов Swift 5+ :

@discardableResult
public prefix func ++<T: Numeric>(i: inout T) -> T {
    i += 1
    return i
}

@discardableResult
public postfix func ++<T: Numeric>(i: inout T) -> T {
    defer { i += 1 }
    return i
}

@discardableResult
public prefix func --<T: Numeric>(i: inout T) -> T {
    i -= 1
    return i
}

@discardableResult
public postfix func --<T: Numeric>(i: inout T) -> T {
    defer { i -= 1 }
    return i
}

-3

В Swift 4.1 это можно было сделать так:



    prefix operator ++
    postfix operator ++
    extension Int{
        static prefix func ++(x: inout Int)->Int{
            x += 1
            return x
        }
        static postfix func ++(x: inout Int)->Int{
            x += 1
            return x-1
        }
    }
    //example:
    var t = 5
    var s = t++
    print("\(t) \(s)")


Обратите внимание, что, несмотря на то, что это решение похоже на предыдущие решения в этом посте, они больше не работают в Swift 4.1, как и в этом примере. Также обратите внимание, что тот, кто выше упоминает, что + = является заменой для ++, просто не полностью понимает оператор, поскольку ++ в сочетании с присваиванием на самом деле представляет собой две операции, следовательно, ярлык. В моем примере:var s = t++выполняет две вещи: присваивает значение t переменной s и затем увеличивает t. Если до него идет ++, это те же две операции, выполняемые в обратном порядке. На мой взгляд, рассуждения Apple о том, почему нужно удалить этот оператор (упомянутые в предыдущих ответах), не только ложные рассуждения, но, более того, я считаю, что это ложь, и истинная причина в том, что они не могли заставить свой компилятор справиться с этим. В предыдущих версиях это доставляло им проблемы, поэтому они сдались. Логика «слишком сложный для понимания оператор, следовательно, удаленный» - очевидная ложь, потому что Swift содержит гораздо более сложные и гораздо менее полезные операторы, которые не были удалены. Кроме того, он есть в подавляющем большинстве языков программирования. JavaScript, C, C #, Java, C ++ и многие другие. Программисты с удовольствием этим пользуются. Кому бы ни было сложно понять этот оператор,

Стратегия Swift проста: Apple считает, что программист тупой, и поэтому к нему следует относиться соответственно.

На самом деле Swift, запущенный в сентябре 2014 года, должен был быть где-то еще. Другие языки выросли намного быстрее.

Я могу перечислить множество серьезных ошибок в языке, от серьезных: например, массивы, вставленные по значению, а не по ссылке, до раздражающих: функции с переменными параметрами не могут принимать массив, что и является основной идеей. Я не думаю, что сотрудникам Apple разрешено даже смотреть на другие языки, такие как Java, поэтому они даже не знают, что Apple отстает на световые годы. Apple могла бы принять Java в качестве языка, но в наши дни проблема не в технологиях, а в эго. Если бы они открыли IntelliJ для написания Java, они бы наверняка закрыли свой бизнес, понимая, что на данный момент они не могут и никогда не догонят.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.