Gli operatori "++" e "-" sono stati deprecati Xcode 7.3


139

Sto guardando le note di Xcode 7.3 e noto questo problema.

Gli operatori ++ e - sono stati deprecati

Qualcuno potrebbe spiegare perché è deprecato? E ho ragione che ora nella nuova versione di Xcode userete al posto di ++questo x += 1;

Esempio:

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

Schermata di avviso


6
Penso che questa domanda se esca dallo scopo di stackoverflow principalmente perché tutte le proposte accettate per la rapida evoluzione possono essere trovate in Github, puoi leggere di più sul perché di questa proposta github.com/apple/swift-evolution/blob/master / proposte /…
Victor Sigler,

7
Sto seriamente considerando di tornare a Objective-C. Non vale la pena provare a tenere il passo con tutte le modifiche a Swift.
Greg Brown,

3
@OlegGordiichuk È la cosa che i for-loop come anche lo stile C verrebbero rimossi, vedi questo github.com/Vkt0r/swift-evolution/blob/master/proposals/…, quindi non hai bisogno di usare di più gli operatori ++e--
Victor Sigler,

10
Ci sono troppi cambiamenti di rottura per i miei gusti. Sono tutto per gli improvvisi, ma non voglio davvero passare il tempo a riscrivere parti sostanziali della mia base di codice ogni volta che esce un rilascio di punti Xcode.
Greg Brown,

4
@Fogmeister Non sono sicuro di come potrei essere più chiaro. Preferirei usare Swift, ma non mi sembra abbastanza stabile. Ho lavorato molto con altre lingue in passato e non ho mai incontrato così tanti cambiamenti in così breve tempo. Sento che Apple vuole che tutti adottiamo Swift, ma lo stanno rendendo più difficile di quanto dovrebbe essere.
Greg Brown,

Risposte:


210

Una spiegazione completa qui da Chris Lattner, il creatore di Swift. Riassumo i punti:

  1. È un'altra funzione che devi imparare mentre impari Swift
  2. Non molto più breve di x += 1
  3. Swift non è C. Non dovrebbe portarli oltre solo per compiacere i programmatori C.
  4. Il suo utilizzo principale è in stile C per ciclo: for i = 0; i < n; i++ { ... }che Swift ha alternative migliori, come for i in 0..<n { ... }(C-stile per loop è andando fuori pure )
  5. Può essere difficile da leggere e mantenere, ad esempio, qual è il valore di x - ++xo foo(++x, x++)?
  6. A Chris Lattner non piace.

Per coloro che sono interessati (e per evitare il marciume dei link), le ragioni di Lattner con le sue stesse parole sono:

  1. Questi operatori aumentano l'onere di apprendere Swift come primo linguaggio di programmazione o in qualsiasi altro caso in cui non si conoscono già questi operatori da una lingua diversa.

  2. Il loro vantaggio espressivo è minimo: x ++ non è molto più breve di x + = 1.

  3. Swift si discosta già da C in quanto =, + = e altre operazioni simili a assegnazioni restituiscono Void (per una serie di motivi). Questi operatori non sono coerenti con quel modello.

  4. Swift ha potenti funzionalità che eliminano molte delle ragioni comuni per cui potresti usare ++ i in stile C per il loop in altre lingue, quindi sono usate raramente nel codice Swift ben scritto. Queste funzionalità includono il ciclo for-in, gli intervalli, l'enumerazione, la mappa, ecc.

  5. Il codice che utilizza effettivamente il valore del risultato di questi operatori è spesso confuso e sottile per un lettore / manutentore del codice. Incoraggiano il codice "troppo complicato" che può essere carino, ma difficile da capire.

  6. Mentre Swift ha un ordine di valutazione ben definito, qualsiasi codice che dipendesse da esso (come foo (++ a, a ++)) sarebbe indesiderabile anche se fosse ben definito.

  7. Questi operatori sono applicabili a relativamente pochi tipi: scalari a numeri interi e in virgola mobile e concetti simili a iteratori. Non si applicano a numeri complessi, matrici, ecc.

Infine, questi falliscono la metrica di "se non li avessimo già aggiunti, li aggiungeremmo a Swift 3?"


54
Penso che la vera risposta sia il numero 6. Va bene, noi (ex programmatori C, Java, ...) siamo abbastanza flessibili :-). In generale, per il mondo reale sono sufficienti la mutazione, il crossover e la selezione. Io, tu e Cris, siamo tutti risultati di questi tre operatori ...
user3441734

5
Punto 5: quelli erano sempre dipendenti dall'implementazione in C, e nessuno con alcun senso li ha mai fatti. Definisci semplicemente il comportamento e ci abitueremo. Meglio che dover tornare indietro e cambiare il vecchio codice perfettamente buono senza una vera ragione.
Echelon

3
Mi piace il punto 3. Non puoi essere incatenato al contratto di eredità per sempre. Adoro C ma stai creando un nuovo linguaggio di programmazione; ha senso iniziare con l'ardesia pulita come è necessario.
Nicolas Miari,

8
È perché a Apple piace costringerti a pensare come loro. Penso che sia perfettamente perfetto e utilizzato ovunque sia necessario incrementare o decrimentare una variabile. Non è qualcosa che "devi imparare", farai bene senza di essa. E # 5 è solo un codice scritto male, cose del genere che non ho mai visto. Quindi # 6 lo è. È deprimente che mi faccia grattare la testa e fare una ricerca su Google, quindi grazie per aver perso il mio tempo Chris.
csga5000,

4
@ csga5000 Questo è un argomento piuttosto debole considerando che puoi semplicemente definire l'operatore da solo se lo desideri davvero. Non ha nulla a che fare con la mela che vuole che le persone pensino come loro. Semplicemente non si adatta alla lingua. Se ++non esistesse nei linguaggi in stile C, nessuno nella loro mente corretta guarderebbe al design di Swift 3.0 e penserebbe che un ++operatore sarebbe una bella aggiunta ad esso.
overactor

37

Mi rendo conto che questo commento non risponde alla domanda, tuttavia potrebbero esserci persone in cerca di una soluzione su come far funzionare questi operatori e tale soluzione può essere trovata in fondo. 😇

Personalmente preferisco ++e --operatori. Non posso essere d'accordo con l'opinione che siano difficili o difficili da gestire. Una volta che lo sviluppatore capisce cosa fanno questi operatori (e stiamo parlando di cose piuttosto semplici) il codice dovrebbe essere molto chiaro.

Nella spiegazione del motivo per cui gli operatori sono stati deprecati viene menzionato che il loro uso principale era in stile C per i loop. Non so per gli altri, ma io personalmente non uso loop in stile C a tutti e ci sono ancora molti altri luoghi o situazioni in cui ++o --operatore è utile.

Vorrei anche menzionare che varName++restituisce un valore in modo che possa essere utilizzato nel returnmentre varName += 1no.

Per ognuno di voi che desidera far funzionare questi operatori, ecco la soluzione:

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
}

Non mi piaci return (x - 1)per gli operatori postfix - IMHO è più pulito nel mantenere la semantica che restituiscono (una copia del) valore originale piuttosto che quello che ottieni se lo faix + 1 - 1
Alnitak,

Neanche a me piace, ma non conosco altri modi (migliori, più puliti) per farlo. Non capisco perfettamente il tuo secondo punto.
0101

1
Vedo, non volevo farlo solo per creare un'altra variabile (o piuttosto costante in questo caso). Se stiamo parlando Intsolo di allora, il risultato di (x + 1)sarà traboccato, il che interromperà l'esecuzione e quindi result - 1non verrà nemmeno eseguito. Altri tipi di dati come Doublead esempio si comportano in modo diverso, quindi devo indagare su questo.
0101

3
Puoi usarlo anche deferper questo. defer { x += 1 }; return x
Tim Vermeulen,

4
perché non usare generici e scrivere questo in poche righe?
μολὼν.λαβέ

22

Apple ha rimosso ++e reso molto più semplice con un altro vecchio modo tradizionale.

Invece di ++, devi scrivere +=.

Esempio:

var x = 1

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

Allo stesso modo per l'operatore di decremento --, è necessario scrivere-=

Esempio:

var x = 1

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

Per i forloop:

Esempio di incremento:

Invece di

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

Tu puoi scrivere:

//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)")
}

Esempio di decremento:

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

Tu puoi scrivere:

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)
}

Spero che questo ti aiuti!


Non hanno sostituito nulla; +=era lì da sempre.
Nicolas Miari,

@NicolasMiari Sì, sto solo modificando con un formato molto migliore
Sohil R. Memon,

@NicolasMiari Puoi per favore controllare ora?
Sohil R. Memon,

3
Che dire di ++ie --i?
Zigii Wong,

7

Chris Lattner è andato in guerra contro ++ e -. Scrive: “Il codice che utilizza effettivamente il valore del risultato di questi operatori è spesso confuso e sottile per un lettore / manutentore del codice. Incoraggiano il codice "troppo complicato" che può essere carino, ma difficile da capire ... Mentre Swift ha un ordine di valutazione ben definito, qualsiasi codice che dipendesse da esso (come foo (++ a, a ++)) sarebbe indesiderabile anche se era ben definito ... questi falliscono la metrica di "se non li avessimo già aggiunti, li aggiungeremmo a Swift 3?" "

Apple voleva mantenere un linguaggio pulito, chiaro, non confuso e diretto al punto. E così hanno deprecato ++ e - keyword.


9
Pulito? Guarda questo inferno di callback e chiamalo pulito? Non sono d'accordo ... E aggiungerei: lascia il ++ & - solo
mcatach il

22
qualcosa di simile ...for i in 0.stride(to: 10, by: 2)...o ...for i in (1...10).reverse()...è pulito ?!
mad_manny

6
Sono d'accordo. L'argomento "pulito" è fondamentalmente contraddittorio rispetto al resto di Swift. Provenendo da Objective-C, che è oggettivamente impuro, è abbastanza difficile accettare "pulito" come obiettivo del linguaggio Apple.
Adrian Bartolomeo

2
Prova ad analizzare json e swift e dimmi quanto è pulito.
nickthedude

6

Schermata di avviso

Il Fix-it featuredi Xcode dà una risposta chiara a questa.

Soluzione all'avvertimento

Sostituire ++ increment operatorcon vecchio stilevalue += 1 (operatore a mano corta) e -- decrement operatorconvalue -= 1


6

Per Swift 4, è possibile ripristinare gli operatori ++e --come estensioni per Inte altri tipi. Ecco un esempio:

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
    }
}

Funziona allo stesso modo per gli altri tipi, come ad esempio UIInt, Int8, Float, Double, etc.

Puoi incollare queste estensioni in un singolo file nella directory principale e saranno disponibili per l'uso all'interno di tutti gli altri file lì.

Ho notato un paio di voti negativi per la mia risposta qui, non appena l'ho pubblicata. Che prendo come un disaccordo filosofico, piuttosto che una critica al funzionamento del mio codice. Funziona perfettamente, se lo controlli in un parco giochi.

Il motivo per cui ho pubblicato questa risposta è perché non sono d'accordo nel rendere i linguaggi di programmazione per computer inutilmente diversi l'uno dall'altro.

Avere molte somiglianze tra le lingue le rende più facili da imparare e passare da una lingua all'altra.

Gli sviluppatori utilizzano normalmente diversi linguaggi di programmazione, anziché solo uno. Ed è una vera seccatura passare da una lingua all'altra, quando non ci sono convenzioni e nessuna standardizzazione comune tra le lingue.

Credo che ci dovrebbero essere differenze di sintassi tra le lingue solo quanto necessario, e non più di così.


Adoro quando le lingue “osano” essere diverse. Sinceramente ci sono troppi linguaggi di "sintassi C", e C è stato progettato TANTO tempo fa ... ci sono stati oltre 50 anni di esperienza linguistica ... a prescindere, poiché questa risposta non è andata a buon fine sugli operatori, ancora un voto.
user2864740

5

Ecco una versione generica di alcuni dei codici pubblicati finora. Vorrei esprimere le stesse preoccupazioni degli altri: è consigliabile non usarli in Swift. Sono d'accordo che questo potrebbe essere fonte di confusione per coloro che leggono il tuo codice in futuro.

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
}

Questo può anche essere scritto come estensione sul tipo numerico.


Ho aggiunto @discardableResulta ciascuna di queste funzioni per mettere a tacere l'avvertimento sul valore di ritorno che non viene utilizzato; altrimenti esattamente quello che stavo cercando.
Devin Lane,

4

Dai documenti :

Gli operatori di incremento / decremento in Swift sono stati aggiunti molto presto nello sviluppo di Swift, come riporto da C. Questi sono stati aggiunti senza troppe considerazioni e da allora non sono stati pensati molto. Questo documento fornisce un nuovo sguardo su di essi e alla fine ci consiglia di rimuoverli del tutto, poiché sono confusi e non portano il loro peso.


In altre parole, questa operazione è troppo costosa per essere utilizzata?
Oleg Gordiichuk,

2
github.com/apple/swift-evolution/blob/master/proposals/… qui puoi leggerlo, ma non è perché è costoso, ma piuttosto design del linguaggio.
Dániel Nagy,

Così come andersen Swift
lascerà

2
@OlegGordiichuk bene direi che vogliono sottolineare che Swift non è un superset di C a differenza di Objective-C.
Dániel Nagy,

1
@mah molto di quello che hai detto non ha alcun senso. "Non orientato verso gli sviluppatori esistenti" in che modo? Allo stesso modo in cui Java non è orientato verso gli sviluppatori PHP? "orientato verso quelli che potrebbero non avere la tendenza ad essere sviluppatori"? Sì, perché tutti quei non sviluppatori là fuori stanno mordendo la mano con la programmazione orientata al protocollo e generici. "Un modo per abilitare una buona progettazione" basta dare un'occhiata a SO, vedrai che nessun linguaggio di programmazione può "abilitare una buona progettazione".
Nebbia

0
var value : Int = 1

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

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

Questo è sicuramente un aspetto negativo, giusto?


5
Intendi elegante come in "devi ricordare tutte le sottigliezze del linguaggio di programmazione C, altrimenti non è immediatamente ovvio se la prima chiamata restituisce 1 o 2"? Penso che tutti possiamo risparmiare qualche altra riga di codice in cambio di non passare qualche minuto a grattarci la testa cercando di trovare un bug causa di un errore sciocco ...
Nicolas Miari

0

Dal momento che in Swift non si lavora mai veramente con i puntatori, secondo me è sensato rimuovere gli operatori ++e --. Tuttavia, se non riesci a vivere senza, puoi aggiungere queste dichiarazioni dell'operatore Swift 5+ al tuo progetto:

@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

In Swift 4.1 potrebbe essere ottenuto in questo modo:



    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)")


Si noti che nonostante questa soluzione sia simile alle soluzioni precedenti in questo post, non funzionano più in Swift 4.1 e questo esempio funziona. Si noti inoltre che chiunque sopra menziona che + = è un sostituto di ++ semplicemente non capisce completamente l'operatore poiché ++ combinato con l'assegnazione è in realtà due operazioni, quindi un collegamento. Nel mio esempio:var s = t++fa due cose: assegna il valore di t a se quindi incrementa t. Se ++ viene prima, sono le stesse due operazioni eseguite in ordine inverso. A mio avviso, il ragionamento di Apple sul perché rimuovere questo operatore (menzionato nelle risposte precedenti), non è solo un ragionamento falso, ma credo inoltre che sia una bugia e il vero motivo è che non sono stati in grado di far gestire il proprio compilatore. Ha dato loro problemi nelle versioni precedenti, quindi hanno rinunciato. La logica di "operatore troppo complicato per capire, quindi rimosso" è ovviamente una bugia perché Swift contiene operatori molto più complicati e molto meno utili che non sono stati rimossi. Inoltre, la stragrande maggioranza dei linguaggi di programmazione ce l'ha. JavaScript, C, C #, Java, C ++ e molti altri ancora. I programmatori lo usano felicemente. Per chi è troppo difficile capire questo operatore per,

La strategia alla base di Swift è semplice: Apple ritiene che il programmatore sia stupido e quindi dovrebbe essere trattato di conseguenza.

La verità è che Swift, lanciato a settembre 2014, doveva ormai essere da qualche altra parte. Altre lingue sono cresciute molto più velocemente.

Posso elencare molti errori importanti nel linguaggio, da quelli gravi: come gli array incollati per valore e non per riferimento, a quelli fastidiosi: le funzioni dei parametri variadici non possono accettare un array che è l'idea alla base. Non penso che i dipendenti di Apple possano nemmeno guardare altre lingue come Java, quindi non sanno nemmeno che Apple è indietro di anni luce. Apple avrebbe potuto adottare Java come linguaggio, ma oggigiorno la sfida non è la tecnologia, ma l'ego lo è. Se avessero aperto IntelliJ per scrivere un po 'di Java, avrebbero sicuramente chiuso la loro attività capendo che a questo punto, non possono e non potranno mai recuperare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.