Cosa significa un punto esclamativo nella lingua Swift?


518

La guida al linguaggio di programmazione Swift ha il seguente esempio:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { println("\(name) is being deinitialized") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { println("Apartment #\(number) is being deinitialized") }
}

var john: Person?
var number73: Apartment?

john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)

//From Apple's “The Swift Programming Language” guide (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)

Quindi, quando assegnano l'appartamento alla persona, usano un punto esclamativo per "scartare l'istanza":

john!.apartment = number73

Cosa significa "scartare l'istanza"? Perché è necessario In che modo è diverso dal solo fare quanto segue:

john.apartment = number73

Sono molto nuovo nella lingua di Swift. Sto solo cercando di buttare giù le basi.


AGGIORNAMENTO:
Il grosso pezzo del puzzle che mi mancava (non indicato direttamente nelle risposte - almeno non al momento della stesura di questo) è che quando fai quanto segue:

var john: Person?

ciò NON significa che " johnè di tipo Persone potrebbe essere nullo", come inizialmente pensavo. Lo stavo semplicemente fraintendendo Persone Person?sono tipi completamente separati. Una volta che ho capito che, tutto il resto ?, la !follia e le grandi risposte di seguito, avevano molto più senso.

Risposte:


530

Cosa significa "scartare l'istanza"? Perché è necessario

Per quanto posso allenarmi (anche per me è una novità) ...

Il termine "incartato" implica che dovremmo considerare una variabile opzionale come un regalo, avvolta in una carta lucida, che potrebbe (purtroppo!) Essere vuota .

Se "racchiuso", il valore di una variabile opzionale è un enum con due possibili valori (un po 'come un valore booleano). Questa enumerazione descrive se la variabile contiene un valore ( Some(T)) o no ( None).

Se esiste un valore, questo può essere ottenuto "scartando" la variabile (ottenendo il Tda Some(T)).

In cosa john!.apartment = number73differisce da john.apartment = number73? (Parafrasato)

Se si scrive il nome di una variabile opzionale (ad es. Testo john, senza il !), questo si riferisce all'enum "wrapped" (Some / None), non al valore stesso (T). Cosìjohn non è un'istanza di Persone non ha un apartmentmembro:

john.apartment
// 'Person?' does not have a member named 'apartment'

Il Personvalore reale può essere scartato in vari modi:

  • "involucro forzato": john! (fornisce il Personvalore se esiste, errore di runtime se è zero)
  • "associazione facoltativa": if let p = john { println(p) } (esegue il printlnse il valore esiste)
  • "concatenamento opzionale": john?.learnAboutSwift() (esegue questo metodo inventato se il valore esiste)

Immagino che tu scelga uno di questi modi per scartarlo, a seconda di cosa dovrebbe accadere nel caso zero e di quanto sia probabile. Questo design del linguaggio impone la gestione esplicita del caso zero, che suppongo migliori la sicurezza su Obj-C (dove è facile dimenticare di gestire il caso zero).

Aggiornare :

Il punto esclamativo viene utilizzato anche nella sintassi per dichiarare "Optionals implicitamente non confezionati".

Negli esempi finora, la johnvariabile è stata dichiarata comevar john:Person? ed è un'opzione. Se si desidera il valore effettivo di quella variabile, è necessario scartarlo, utilizzando uno dei tre metodi sopra.

Se fosse dichiarato come var john:Person!invece, la variabile sarebbe un Opzionale implicitamente non imballato (vedi la sezione con questa intestazione nel libro di Apple). Non è necessario scartare questo tipo di variabile quando si accede al valore e johnpuò essere utilizzato senza sintassi aggiuntiva. Ma il libro di Apple dice:

Gli opzionali implicitamente non scartati non dovrebbero essere usati quando esiste la possibilità che una variabile diventi nulla in un secondo momento. Utilizzare sempre un tipo facoltativo normale se è necessario verificare un valore nullo durante la durata di una variabile.

Aggiornamento 2 :

L'articolo " Interessanti funzionalità di Swift " di Mike Ash fornisce alcune motivazioni per i tipi opzionali. Penso che sia una scrittura fantastica e chiara.

Aggiornamento 3 :

Un altro articolo utile sull'uso facoltativo implicitamente da scartare per il punto esclamativo: " Swift and the Last Mile " di Chris Adamson. L'articolo spiega che questa è una misura pragmatica utilizzata da Apple per dichiarare i tipi utilizzati dai loro framework Objective-C che potrebbero contenere zero. Dichiarare un tipo come facoltativo (utilizzo ?) o implicitamente non imballato (utilizzo! ) è "un compromesso tra sicurezza e convenienza". Negli esempi forniti nell'articolo, Apple ha scelto di dichiarare i tipi come implicitamente non imballati, rendendo il codice chiamante più conveniente, ma meno sicuro.

Forse Apple potrebbe sfogliare i loro framework in futuro, rimuovendo l'incertezza dei parametri implicitamente non confezionati ("probabilmente mai zero") e sostituendoli con parametri facoltativi ("certamente potrebbe essere nullo in particolare [si spera, documentato!]") O standard non -optional ("is never nil") dichiarazioni, basate sul comportamento esatto del loro codice Objective-C.


Non sono sicuro di questa spiegazione. Se esegui semplicemente il codice senza il! restituisce comunque il valore effettivo. Forse il ! è per la velocità?
Richard Washington,

OK. Quindi i documenti parlano dell'uso! quando sai per certo che può essere scartato. Ma puoi eseguire il codice bene senza di esso (una quarta opzione per il tuo elenco - implicita da scartare) E senza controllare prima. Si restituisce il valore o zero se zero. Ma se sai per certo che non è zero, allora usa! ...... ma non riesco ancora a capire perché lo faresti?
Richard Washington,

2
Ciao @RichardWashington - Ho aggiunto un aggiornamento alla mia risposta che spero chiarisca un po 'di questo.
Ashley,

L'aggiornamento 3 è esattamente quello che sto cercando. Prima di leggerlo pensavo che Apple stesse mentendo quando hanno restituito qualcosa come NSURLCredential! che in realtà potrebbe essere nullo.
Pollice d'oro,

Grazie per la fantastica risposta @Ashley. Dopo aver letto questa risposta e alcuni esempi del codice rapido di Apple, mi sembra davvero che in questo compromesso tra sicurezza e produttività, di solito è meglio essere sul lato più sicuro. Un'eccezione notevole che ho riscontrato è quando Apple utilizza il wrapping forzato per gli elementi dell'interfaccia utente, il che ha senso perché prima, gli elementi dell'interfaccia utente sono in genere facoltativi quando coinvolgono uno storyboard (in quanto non sono assegnati un valore a livello di codice), e in secondo luogo perché sono quasi mai zero a meno che il loro controller di visualizzazione contenente sia nullo, nel qual caso questa discussione è discutibile.
Mihir,

127

Ecco cosa penso sia la differenza:

var john: Person?

Significa che John può essere nullo

john?.apartment = number73

Il compilatore interpreterà questa riga come:

if john != nil {
    john.apartment = number73
}

Mentre

john!.apartment = number73

Il compilatore interpreterà questa riga semplicemente:

john.apartment = number73

Quindi, usando! scarterà l'istruzione if e la farà funzionare più velocemente, ma se john è zero, si verificherà un errore di runtime.

Quindi, avvolgere qui non significa che è avvolto in memoria, ma significa che è avvolto in codice, in questo caso è avvolto con un'istruzione if e, poiché Apple presta molta attenzione alle prestazioni in fase di esecuzione, vogliono darti un modo per fai funzionare la tua app con le migliori prestazioni possibili.

Aggiornare:

Tornando a questa risposta dopo 4 anni, poiché ho ottenuto la massima reputazione da esso in StackOverflow :) Ho capito male il significato di scartare in quel momento. Ora dopo 4 anni credo che il significato di scartare qui sia espandere il codice dalla sua forma originale compatta. Significa anche rimuovere la vaghezza attorno a quell'oggetto, poiché non siamo sicuri per definizione che sia nullo o no. Proprio come la risposta di Ashley sopra, pensala come un regalo che non può contenere nulla al suo interno. Ma penso ancora che lo scartare sia scartare il codice e non scartare basato sulla memoria come usare enum.


9
Nel mio parco giochi john.apartment = number73 non viene compilato, devi specificare john? .Apartment = number73
Chuck Pinkert

2
@ChuckPinkert ha ragione, la quarta riga dovrebbe essere modificata in john? .Apartment = number73, bella risposta però!
Bruce

john.apartment = number73 dà errore: valore del tipo opzionale 'Person?' non scartato: intendevi usare "!" o '?'?
Spiderman,

4
Lo svolgitore non ha nulla a che fare con le prestazioni di wrt. Il "controllo zero" deve ancora essere eseguito in fase di runtime, l'unica differenza è che verrà generato un errore di runtime nel caso in cui non sia presente alcun valore in Opzionale.
madidier,

67

TL; DR

Cosa significa un punto esclamativo nella lingua Swift?

Il punto esclamativo dice effettivamente: "So che questo optional ha sicuramente un valore; per favore, usalo. " Questo è noto come rimozione non forzata del valore dell'opzione:

Esempio

let possibleString: String? = "An optional string."
print(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."

let assumedString: String! = "An implicitly unwrapped optional string."
print(assumedString)  // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string."

Fonte: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399


11
La tua risposta è fantastica perché capisco cosa sta succedendo ora. Quello che non capisco è il motivo per cui esistono opzioni implicitamente non scartate. Perché creare qualcosa definito come una stringa opzionale implicitamente da scartare, piuttosto che un normale tipo di stringa? Il loro uso da allora in poi è lo stesso. Cosa mi sto perdendo?
Pachun,

Questo non sembra più essere vero. In Swift 5 sostitu, se lo faccio let f: String! = "hello"e poi print(f), l'output è Optional("hello")invece di solo "hello".
numbermaniac

37

Se john fosse un var facoltativo (dichiarato così)

var john: Person?

allora sarebbe possibile per john non avere alcun valore (nel linguaggio ObjC, valore zero)

Il punto esclamativo dice sostanzialmente al compilatore "So che questo ha un valore, non è necessario verificarlo". Se non si desidera utilizzarlo, è possibile verificarlo condizionatamente:

if let otherPerson = john {
    otherPerson.apartment = number73
}

L'interno di questo valuterà solo se John ha un valore.


4
Grazie per la risposta, ora capisco cosa dice il punto esclamativo, sto ancora cercando di avvolgere la mia testa sul perché ... Hai detto che dice al compilatore "So che questo ha un valore, non è necessario testarlo esso". Cosa mi compra quando il compilatore non lo verifica? Senza il punto esclamativo, il compilatore genererà un errore (non ho ancora un ambiente in cui posso testare Swift)? È il ! 100% necessario per tutti i varianti opzionali? Se è così, perché Apple si è preoccupato di farlo, invece di renderlo così la mancanza di! significa "So che questo ha un valore, non è necessario testarlo"?
Troy,

"il compilatore genererà un errore" - no funziona ancora correttamente restituendo il valore come previsto. Non capisco. È il ! solo per la velocità quando sei sicuro forse?
Richard Washington,

In effetti in seguito i documenti parlano di optionals implicitamente da scartare usando l'esempio di seguito: “let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.” Ma funziona bene con no! Qualcosa sembra strano qui.
Richard Washington,

3
@RichardWashington Sei confuso per una buona ragione! Gli esempi nei documenti tralasciano alcune cose e sono fuorvianti perché tutto ciò che fanno è usare println. Apparentemente, ci sono almeno un paio di casi in cui non è necessario scartare gli optionals. Uno è quando si utilizza println. Un altro è quando si utilizza l'interpolazione di stringhe. Quindi, forse println e l'interpolazione delle stringhe non vengono scartate sotto le copertine? Forse qualcuno ha più intuizioni su questo. Guardare le definizioni dell'intestazione Xcode6 Beta non mi ha rivelato nulla di questa magia.
mbeaty

Sì, lo capisco John?e Johnsono due tipi diversi. Uno è di tipo Persona facoltativa e l'altro tipo di persona. La persona facoltativa deve essere scartata prima di poterla estrarre. Ma come dici tu, questo sembra accadere almeno in queste circostanze senza dover fare davvero nulla. Questo sembra rendere il! ridondante. A meno che il! è SEMPRE facoltativo, ma una cosa consigliata da fare per rilevare errori di compilazione. Un po 'come assegnare variabili / lettere a un tipo particolare può essere esplicito let John: Person = ...ma può anche essere dedotto let John = ....
Richard Washington,

27

Qualche prospettiva di quadro generale da aggiungere alle altre risposte utili ma più incentrate sui dettagli:

In Swift, il punto esclamativo appare in diversi contesti:

  • Disimballaggio forzato: let name = nameLabel!.text
  • Opzionali impliciti da scartare: var logo: UIImageView!
  • Colata forzata: logo.image = thing as! UIImage
  • Eccezioni non gestite: try! NSJSONSerialization.JSONObjectWithData(data, [])

Ognuno di questi è un costrutto di linguaggio diverso con un significato diverso, ma tutti hanno tre cose importanti in comune:

1. I punti esclamativi aggirano i controlli di sicurezza in fase di compilazione di Swift.

Quando usi !Swift, stai essenzialmente dicendo: "Ehi, compilatore, so che pensi che qui possa accadere un errore , ma so con assoluta certezza che non lo farà mai".

Non tutto il codice valido si inserisce nella casella del sistema di compilazione del tempo di compilazione di Swift - o del controllo statico del tipo di qualsiasi lingua, del resto . Ci sono situazioni in cui puoi logicamente dimostrare che non si verificherà mai un errore, ma non puoi provarlo al compilatore . Ecco perché i designer di Swift hanno aggiunto queste funzionalità in primo luogo.

Tuttavia, ogni volta che lo usi ! , stai escludendo un percorso di recupero per un errore, il che significa che ...

2. I punti esclamativi sono potenziali arresti anomali.

Un punto esclamativo dice anche: "Ehi Swift, sono così certo che questo errore non può mai accadere che è meglio per te bloccare la mia intera app di quanto non lo sia per me codificare un percorso di recupero."

È un'affermazione pericolosa. esso può essere quella giusta: nel codice mission-critical in cui avete pensato duro a invarianti del codice, può essere che la produzione fasulla è peggio di un incidente.

Tuttavia, quando vedo !in natura, raramente viene utilizzato in modo così consapevole. Invece, troppo spesso significa "questo valore era facoltativo e non pensavo davvero troppo al perché potesse essere nullo o a come gestire correttamente quella situazione, ma aggiungendo! fatta compilare ... quindi il mio codice è corretto, giusto?"

Fai attenzione all'arroganza del punto esclamativo. Anziché…

3. I punti esclamativi sono usati con parsimonia.

Ognuno di questi !costrutti ha una ?controparte che ti costringe a gestire il caso di errore / zero:

  • Involucro condizionale: if let name = nameLabel?.text { ... }
  • Optional: var logo: UIImageView?
  • Cast condizionali: logo.image = thing as? UIImage
  • Eccezioni zero-on-failure: try? NSJSONSerialization.JSONObjectWithData(data, [])

Se sei tentato di usare !, è sempre bene considerare attentamente perché non stai usando ?. L'arresto anomalo del programma è davvero l'opzione migliore se l' !operazione non riesce? Perché quel valore è opzionale / disponibile?

Esiste un ragionevole percorso di recupero che il tuo codice potrebbe prendere nel caso zero / errore? In tal caso, codificalo.

Se non può essere nulla, se l'errore non può mai accadere, allora c'è un modo ragionevole per rielaborare la tua logica in modo che il compilatore lo sappia? Se è così, fallo; il tuo codice sarà meno soggetto a errori.

Ci sono momenti in cui non esiste un modo ragionevole per gestire un errore e semplicemente ignorare l'errore - e quindi procedere con dati errati - sarebbe peggio dell'arresto anomalo. Quelli sono i tempi per usare lo scartamento forzato.

Cerco periodicamente tutto il mio codebase !e controllo ogni suo utilizzo. Pochissimi usi resistono al controllo. (Al momento della stesura di questo documento, l'intero framework Siesta ne contiene esattamente due esempi .)

Questo non vuol dire che non dovresti mai usare il !tuo codice - solo che dovresti usarlo consapevolmente e non renderlo mai l'opzione predefinita.


func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) } Dato 3. c'è un modo migliore per scriverlo?
jenson-button-event,

Puoi direfunc isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
rkgibson2 il

I punti esclamativi non eludono alcun controllo di sicurezza. Si ottiene un arresto anomalo garantito se l'opzione è nulla. L'opzione è sempre selezionata. È solo un modo molto brutale per effettuare un controllo di sicurezza.
gnasher729,

@ gnasher729 Come indicato dalla risposta, elude i controlli di sicurezza in fase di compilazione a favore di un errore di runtime sicuro .
Paul Cantrell,

24

johnè un optional var. Quindi può essere contiene un nilvalore. Per assicurarsi che il valore non sia nullo, utilizzare !a alla fine del varnome.

Dalla documentazione

“Una volta che sei sicuro che l'opzione contenga un valore, puoi accedere al valore sottostante aggiungendo un punto esclamativo (!) Alla fine del nome dell'opzione. Il punto esclamativo dice effettivamente: "So che questo optional ha sicuramente un valore; per favore, usalo. "

Un altro modo per controllare un valore diverso da zero è

    if let j = json {
        // do something with j
    }

1
Sì, l'avevo visto nella documentazione, ma sembra ancora inutile ... come, per me, john.apartment = number73dice anche "So che questo optional ha sicuramente un valore; per favore, usalo." ...
Troy

6
Sì, ma il punto è che per impostazione predefinita Swift cerca di rilevare errori in fase di compilazione. Se sai o pensi di sapere che questa variabile non può contenere nulla, puoi rimuovere quel segno di spunta usando il punto esclamativo.
Lassej,

16

Ecco alcuni esempi:

var name:String = "Hello World"
var word:String?

Dov'è wordun valore opzionale. significa che può contenere o meno un valore.

word = name 

Qui nameha un valore in modo che possiamo assegnarlo

var cow:String = nil
var dog:String!

Dove dogviene forzatamente scartato, significa che deve contenere un valore

dog = cow

L'applicazione si arresterà in modo anomalo perché siamo assegnati nila non imballati


1
var c:Int = nilotterrà: "Zero non può inizializzare il tipo specificato 'int'"
Asususer

15

In questo caso...

var John: Persona!

significa che inizialmente John avrà un valore nullo, verrà impostato e una volta impostato non sarà più guidato da zero. Pertanto, per comodità, posso utilizzare la sintassi più semplice per accedere a una variante facoltativa poiché si tratta di una "Opzione implicitamente non scartata"


1
Grazie. Avevo anche trovato il seguente link che spiega questo. Questo tipo di tipo è chiamato "opzione implicitamente da scartare". stackoverflow.com/questions/24122601/...
Kaydell

5

Se provenite da un linguaggio della famiglia C, penserete "puntatore all'oggetto di tipo X che potrebbe essere l'indirizzo di memoria 0 (NULL)", e se venite da un linguaggio tipizzato dinamicamente sarete pensando "Oggetto che è probabilmente di tipo X ma potrebbe essere di tipo indefinito". Nessuno di questi è effettivamente corretto, anche se in modo rotatorio il primo è vicino.

Il modo in cui dovresti pensarci è come se fosse un oggetto come:

struct Optional<T> {
   var isNil:Boolean
   var realObject:T
}

Quando stai testando il tuo valore opzionale con il foo == nilsuo ritorno reale foo.isNil, e quando dici foo!che sta tornando foo.realObjectcon un'affermazione che foo.isNil == false. È importante notare questo perché se fooeffettivamente è nullo quando lo faifoo! , questo è un errore di runtime, quindi in genere dovresti utilizzare invece una condizione condizionale a meno che tu non sia molto sicuro che il valore non sarà zero. Questo tipo di inganno significa che la lingua può essere fortemente digitata senza costringerti a verificare se i valori sono nulli ovunque.

In pratica, non si comporta davvero così perché il compilatore svolge il lavoro. A un livello elevato esiste un tipo a Foo?cui è separato Fooe che impedisce alle funzioni che accettano il tipo Foodi ricevere un valore nullo, ma a un livello basso un valore opzionale non è un oggetto vero perché non ha proprietà o metodi; è probabile che in realtà si tratti di un puntatore che può essere NULL (0) con il test appropriato quando si esegue il riavvolgimento forzato.

C'è un'altra situazione in cui vedresti un punto esclamativo su un tipo, come in:

func foo(bar: String!) {
    print(bar)
}

Ciò equivale all'incirca all'accettazione di un optional con un involucro forzato, ovvero:

func foo(bar: String?) {
    print(bar!)
}

Puoi usarlo per avere un metodo che accetta tecnicamente un valore opzionale ma avrà un errore di runtime se è nullo. Nell'attuale versione di Swift, ciò apparentemente ignora l'asserzione non-nulla, quindi si avrà invece un errore di basso livello. Generalmente non è una buona idea, ma può essere utile durante la conversione di codice da un'altra lingua.



3

Se hai familiarità con C #, questo è come i tipi Nullable che sono anche dichiarati usando un punto interrogativo:

Person? thisPerson;

E il punto esclamativo in questo caso equivale ad accedere alla proprietà .Value del tipo nullable in questo modo:

thisPerson.Value

2

Nelle variabili obiettivo C senza valore erano uguali a "zero" (era anche possibile utilizzare i valori "zero" uguali a 0 e falso), quindi era possibile utilizzare le variabili nelle istruzioni condizionali (le variabili con valori sono uguali a "VERO" 'e quelli senza valori erano uguali a' FALSE ').

Swift fornisce la sicurezza del tipo fornendo "valore opzionale". cioè Impedisce che errori formati assegnino variabili di diverso tipo.

Quindi in Swift, solo i booleani possono essere forniti su dichiarazioni condizionali.

var hw = "Hello World"

Qui, anche se 'hw' è una stringa, non può essere utilizzata in un'istruzione if come nell'obiettivo C.

//This is an error

if hw

 {..}

Per questo deve essere creato come,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}

2

Il ! alla fine di un oggetto dice che l'oggetto è un optional e da scartare se altrimenti può restituire uno zero. Questo è spesso usato per intrappolare errori che altrimenti andrebbero in crash il programma.


2

In breve (!): Dopo aver dichiarato una variabile e che si è certi che la variabile abbia un valore.

let assumedString: String! = "Some message..."
let implicitString: String = assumedString

altrimenti dovresti farlo dopo ogni passaggio di valore ...

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark

1

John è una persona facoltativa, il che significa che può contenere un valore o essere nullo.

john.apartment = number73

viene usato se john non è un optional. Dato che john non è mai zero, possiamo essere certi che non chiamerà appartamento con un valore zero. Mentre

john!.apartment = number73

promette al compilatore che John non è zero, quindi scartare il valore facoltativo per ottenere il valore di John e accedere alla proprietà dell'appartamento di John. Usalo se sai che John non è zero. Se lo chiami su uno zero opzionale, otterrai un errore di runtime.

La documentazione include un bell'esempio per l'utilizzo di questa opzione in cui converterNumber è facoltativo.

if convertedNumber {
    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}

Stai dicendo che se John è nullo, e io vado john.apartment = number73, che NON si tradurrà in un errore se non metto un "!" dopo john?
Troy,

Se john è un optional, devi usare il punto esclamativo per accedere alle sue proprietà perché il compilatore deve sapere che non è nullo. Se non è un optional, non è possibile utilizzare il punto esclamativo.
Connor,

1
Se devo usare un punto esclamativo per TUTTI i varianti opzionali, perché Apple si è nemmeno preoccupato di farlo, invece di farlo in modo che la mancanza di un punto esclamativo significhi la stessa cosa? Sembra inutile gonfiarsi ... O c'è un caso in cui ha senso NON usare un punto esclamativo con un var opzionale?
Troy,

si utilizza il punto esclamativo quando è necessario che facoltativo non sia nullo. Come nel caso dell'accesso alle proprietà di john. potresti fare qualcosa come var jack: persona? = john dove jack è anche un jack opzionale o var: Person = john! dove jack è una persona e non è nulla
Connor

Giusto ma, nell'esempio originale, il fatto che io stia dereferenziando l' johnopzionale non dice al compilatore che ho bisogno che sia diverso da zero? ... E nel tuo var jack: Person = john!esempio, la mancanza di un? dopo che Person ha detto al compilatore che devi johnessere diverso da zero? Nel complesso, !sembra proprio ridondante ... Mi sembra ancora che mi manchi qualcosa nella parte "perché" di !...
Troy,

1

Per dirla semplicemente, i punti esclamativi indicano che un optional è stato scartato. Un facoltativo è una variabile che può avere o meno un valore, quindi puoi verificare se la variabile è vuota, usando un'istruzione if let come mostrato qui , quindi forzare a scartarla. Se forzate a scartare un optional vuoto, il programma si arresterà in modo anomalo, quindi fate attenzione! Gli optionals vengono dichiarati mettendo un punto interrogativo alla fine di un'assegnazione esplicita a una variabile, ad esempio potrei scrivere:

var optionalExample: String?

Questa variabile non ha valore. Se dovessi scartarlo, il programma andrebbe in crash e Xcode ti direbbe che hai provato a scartare un opzionale con un valore pari a zero.

Spero che abbia aiutato.


1

IN SEMPLICI PAROLE

USANDO Il punto esclamativo indica che la variabile deve contenere un valore diverso da zero (non deve mai essere nulla)


1

L'intera storia inizia con una funzione di rapido chiamata vars opzionali. Questi sono i var che possono avere un valore o non avere un valore. In generale swift non ci consente di utilizzare una variabile che non è inizializzata, in quanto ciò potrebbe causare arresti anomali o motivi imprevisti e anche servire da segnaposto per le backdoor. Quindi per dichiarare una variabile il cui valore non è inizialmente determinato si usa un '?'. Quando viene dichiarata una tale variabile, per usarla come parte di un'espressione è necessario scartarla prima dell'uso, scartare è un'operazione attraverso la quale viene scoperto il valore di una variabile, questo vale per gli oggetti. Senza scartare se si tenta di usarli, si avrà un errore di tempo di compilazione. Per scartare una variabile che è una var opzionale, punto esclamativo "!" viene usato.

Ora ci sono momenti in cui sai che a tali variabili opzionali verranno assegnati valori dal sistema, ad esempio o dal tuo programma, ma qualche tempo dopo, ad esempio punti di interfaccia utente, in tale situazione invece di dichiarare una variabile opzionale usando un punto interrogativo "?" noi usiamo "!".

Quindi il sistema sa che questa variabile che è dichiarata con "!" è facoltativo in questo momento e non ha alcun valore ma riceverà un valore più avanti nella sua vita.

Pertanto, il punto esclamativo contiene due usi diversi, 1. Per dichiarare una variabile che sarà facoltativa e riceverà valore sicuramente in seguito 2. Scartare una variabile opzionale prima di usarla in un'espressione.

Spero che sopra le descrizioni evitino troppe cose tecniche.


1

Se lo usi come un optional, scartalo e vede se c'è qualcosa. Se lo usi in un'istruzione if-else è il codice per NOT. Per esempio,

if (myNumber != 3){
 // if myNumber is NOT 3 do whatever is inside these brackets.
)

1

Una variabile facoltativa può contenere un valore o potrebbe non esserlo

caso 1: var myVar:String? = "Something"

caso 2: var myVar:String? = nil

ora se chiedi a myVar !, stai dicendo al compilatore di restituire un valore nel caso in cui 1 ritorni "Something"

nel caso 2 andrà in crash.

Senso ! mark costringerà il compilatore a restituire un valore, anche se non è presente. ecco perché il nome Force Unwrapping .


@Moritz. Non lo so, è così? Non posso rispondere se una domanda ha già una risposta? Sto causando qualche problema o c'è qualcosa di sbagliato nella mia risposta? non capisco Perché lo stai votando per aver risposto correttamente? Ho cercato di rispondere in base alla mia comprensione del concetto. penso che alcune persone lo troveranno utile per una spiegazione chiara e semplice.
Ashish Pisey,

@Moritz Ora questo è costruttivo. Avresti dovuto dirmi questa correzione in primo luogo, se questo fosse il motivo. Grazie per il feedback. l'ho corretto.
Ashish Pisey,

0
Simple the Optional variable allows nil to be stored.

var str : String? = nil

str = "Data"

To convert Optional to the Specific DataType, We unwrap the variable using the keyword "!"

func get(message : String){
   return
}

get(message : str!)  // Unwapped to pass as String

1
Si prega di non scrivere risposte che non aggiungono nulla che non sia già stato coperto da risposte precedenti.
Dalija Prasnikar,

-1

CHIEDILO A TE STESSO

  • Il tipo person?ha un apartmentmembro / proprietà? O
  • Il tipo personha un apartmentmembro / proprietà?

Se non riesci a rispondere a questa domanda, continua a leggere:

Per capire potresti aver bisogno di un livello super-base di comprensione di Generics . Vedi qui . Molte cose in Swift sono scritte usando Generics. Optionals inclusi

Il codice seguente è stato reso disponibile da questo video di Stanford . Consiglio vivamente di guardare i primi 5 minuti

Un opzionale è un enum con solo 2 casi

enum Optional<T>{
    case None
    case Some(T)
}

let x: String? = nil //actually means:

let x = Optional<String>.None

let x :String? = "hello" //actually means:

let x = Optional<String>.Some("hello")

var y = x! // actually means:

switch x {
case .Some(let value): y = value
case .None: // Raise an exception
}

Rilegatura opzionale:

let x:String? = something
if let y = x {
    // do something with y
}
//Actually means:

switch x{
case .Some(let y): print)(y) // or whatever else you like using 
case .None: break
}

quando dici var john: Person?Intendi davvero questo:

enum Optional<Person>{
case .None
case .Some(Person)
}

La enum sopra ha qualche proprietà chiamata apartment? Lo vedi da qualche parte? E ' non è lì a tutti! Tuttavia, se lo scartate, ovvero fate, person!allora ... quello che fa sotto il cofano è:Optional<Person>.Some(Person(name: "John Appleseed"))


Se avessi definito var john: Personinvece di: var john: Person?allora non avresti più avuto bisogno !dell'uso, perché di per Personsé ha un membroapartment


Come discussione futura sul perché l'utilizzo !di scartare a volte non è raccomandato, consultare le Domande e risposte


2
L'uso delle diapositive sopra riportate è probabilmente una violazione del copyright: "... La Stanford University detiene il copyright su tutti i contenuti della nostra collezione iTunes U". , da http://itunes.stanford.edu . Probabilmente è meglio rispondere, con parole tue, al contenuto che hai imparato dal corso che percepisci per rispondere a questa domanda (e invece di usare le diapositive, piuttosto cita parti pertinenti di esse in forma di codice, con riferimenti, naturalmente).
venerdì

2
La tua argomentazione è argumentum ad populum . Comunque, non credo che Stanford verrà qui e farà valere i diritti DMCA , ma è sempre meglio se le tue risposte sono in parole tue basate su fonti ufficiali / valide , e non nella forma di copiare quelle fonti come sopra; specialmente quando parliamo di diapositive protette da copyright: ancora una volta, è meglio citare il contenuto delle diapositive in blocchi di codice (le immagini di codice sono generalmente un no-no qui in SO!).
venerdì

1
Il meta post che ho collegato descrive solo l'approccio SO: s a questo: un post come questo naturalmente non verrà rimosso se un utente casuale lo segnala come violazione del copyright: solo se, ad esempio, un rappresentante di Stanford. dovevano venire qui e poiché il posto da rimuovere avrebbe dovuto quindi applicarlo. Quindi ho scritto " Non credo che Stanford verrà qui e farà valere i diritti DMCA, ..." . Il punto sopra è che ritengo che ciò possa costituire una violazione del copyright (cosa che ritengo errata), ma naturalmente nessuno lo farà mai valere. ...
dfri

1
Ma a parte questo, pubblicare domande o risposte che contengono immagini di codice è sconsigliato per una serie di motivi. Per concludere: ho cercato di sottolineare con questi commenti che credo che questa risposta, nella sua forma attuale, non sia del tutto valida come potrebbe essere, a causa di due motivi principali (diapositive protette da copyright, immagine del codice). Naturalmente nessuno, incluso me stesso, farà nulla al riguardo, lo sto semplicemente indicando come riferimento futuro (o forse ti incoraggio a modificare questo post citando invece i blocchi di codice). D'accordo, iTunes U! :)
venerdì

2
@dfri ha rimosso le immagini
Miele
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.