Оператори "++" та "-" застаріли 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, але вони роблять це складніше, ніж це має бути.
Грег Браун

Відповіді:


210

Повне пояснення тут від Кріса Lattner, творця Свіфта. Я підсуму моменти:

  1. Це ще одна функція, яку ви повинні засвоїти під час навчання Swift
  2. Не набагато коротше x += 1
  3. Свіфт - це не C. Не варто їх переносити лише для того, щоб догодити програмістам C
  4. Основне його використання в C-стилі для циклу:, у for i = 0; i < n; i++ { ... }якого Swift є кращі альтернативи, як for i in 0..<n { ... }(С-стиль для циклу також виходить )
  5. Чи може бути складно читати та підтримувати, наприклад, яка цінність x - ++xчи foo(++x, x++)?
  6. Chris Lattner це не любить.

Для тих, хто цікавиться (і щоб уникнути гниття посилань), причинами Леттнера в його власних словах є:

  1. Ці оператори збільшують навантаження вивчити Swift як першу мову програмування - або будь-який інший випадок, коли ви вже не знаєте цих операторів з іншої мови.

  2. Їх виразна перевага мінімальна - х ++ не набагато коротше, ніж х + = 1.

  3. Swift вже відхиляється від C тим, що =, + = та інші операції, подібні до призначення, повертають Void (з ряду причин). Ці оператори несумісні з цією моделлю.

  4. Swift має потужні функції, які усувають багато поширених причин, коли ви використовуєте ++ i у стилі C для циклу іншими мовами, тому вони порівняно рідко використовуються у добре написаному коді Swift. Ці функції включають цикл для введення, діапазони, перерахування, карту тощо.

  5. Код, який фактично використовує значення результату цих операторів, часто заплутаний і тонкий для читача / підтримувача коду. Вони заохочують "надмірно складний" код, який може бути милим, але важко зрозуміти.

  6. Хоча у Свіфта чітко визначений порядок оцінювання, будь-який код, який залежав від нього (як foo (++ a, a ++)), був би небажаним, навіть якби він був чітко визначений.

  7. Ці оператори застосовні до відносно небагатьох типів: цілочисельні чи скалари з плаваючою комою та поняття, подібні до ітераторів. Вони не застосовуються до складних чисел, матриць тощо.

Нарешті, вони не відповідають показнику "якби у нас їх уже не було, додамо їх до Swift 3?"


54
Я річ, справжня відповідь - це число 6. Це нормально, ми (колишні програмісти C, Java, ...) досить гнучкі :-). Взагалі для реального світу достатньо мутації, кросовера та відбору. Я, ти і Крис, ми всі результати цих трьох операторів ...
user3441734

5
Пункт 5: Це завжди залежало від впровадження C, і ніхто з жодним сенсом їх ніколи не робив. Просто визначте поведінку, і ми звикнемо до неї. Краще ніж повертатися назад та змінювати ідеально хороший старий код без реальних причин.
Ешелон

3
Мені подобається пункт 3. Ви не можете назавжди бути пов'язаними із договором спадщини. Я люблю C, але ви створюєте нову мову програмування; має сенс починати з шиферу так само чисто, як вам потрібно.
Nicolas Miari

8
Це тому, що яблуко любить змушувати думати, як вони. Я думаю, що це абсолютно добре і використовується в будь-якому місці, де потрібно збільшувати чи зменшувати змінну. Це не те, що вам "доведеться вчитися", ви без нього добре зробите. І №5 - це лише погано написаний код, подібного до якого я ніколи не бачив. Отже, №6 це. Зображення цього досить, щоб змусити почухати голову та здійснити пошук у Google, тож спасибі за те, що витратив час Кріс.
csga5000

4
@ csga5000 Це досить слабкий аргумент, враховуючи, що ви можете просто визначити оператора, якщо цього дуже хочете. Це не має нічого спільного з тим, що яблуко хоче, щоб люди думали, як вони. Це просто не відповідає мові. Якби ++не існувало на мовах стилю С, ніхто з розумом не подивився б на дизайн Swift 3.0 і подумає, що ++оператор був би приємним доповненням до нього.
суперкомпетент

37

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

Я особисто віддаю перевагу ++і --операторам. Я не можу погодитися з думкою, що вони складні чи важкі в управлінні. Як тільки розробник зрозуміє, що роблять ці оператори (а ми говоримо про досить прості речі), код повинен бути дуже зрозумілим.

У поясненні того, чому оператори застаріли, зазначається, що їх основне використання було в стилі С для циклів. Я не знаю про інших , але я особисто не використовувати цикли C-стиль на всіх , і є ще багато інших місць або ситуацій , коли ++або --оператор корисний.

Я хотів би також зазначити, що 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)для операторів Postfix - IMHO чистіше підтримувати семантику, яку вони повертають (копію) оригінального значення, а не того, що ви отримуєте, якщо ви це зробитеx + 1 - 1
Alnitak

Мені це теж не подобається, але я не знаю про будь-який інший (кращий, чистіший) спосіб цього зробити. Я не повністю розумію ваш другий пункт.
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)
}

Сподіваюся, це допомагає!


Вони нічого не замінили; +=був там весь час.
Nicolas Miari

@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

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 був розроблений НАДОЛЬГО часу тому. Існує понад 50 років мовного досвіду .. незалежно, оскільки ця відповідь не перетворилася на тираду щодо операторів, як і раніше виступ
користувач2864740

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. Вони були додані без особливого розгляду, і не думали про те багато з того часу. Цей документ дає новий погляд на них, і в кінцевому підсумку рекомендує нам просто видалити їх цілком, оскільки вони плутають і не несуть своєї ваги.


Іншими словами, ця операція занадто дорога, щоб використовувати її?
Олег Гордійчук

2
github.com/apple/swift-evolution/blob/master/proposals/… тут ви можете прочитати про це, але це не тому, що це дорого, а швидше мовний дизайн.
Даніель Надь

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

2
@OlegGordiichuk добре, я б сказав, що вони хочуть підкреслити, що Свіфт - це не надмножина 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"? Я думаю, що ми можемо позбавити кількох додаткових рядків коду в обмін на те, що не витрачаємо кілька хвилин на подряпини голови, намагаючись знайти причину помилки дурною помилкою ...
Nicolas Miari

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.