wake-up-neo.com

Was bedeutet ein Ausrufezeichen in der Sprache Swift?

Das Programmiersprachenhandbuch Swift enthält das folgende Beispiel:

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)

Wenn sie der Person die Wohnung zuweisen, verwenden sie ein Ausrufezeichen, um "die Instanz auszupacken":

john!.apartment = number73

Was bedeutet es, die Instanz zu "entpacken"? Warum ist es notwendig? Wie unterscheidet es sich von den folgenden Schritten:

john.apartment = number73

Ich bin sehr neu in der Swift Sprache. Ich versuche nur, die Grundlagen zu vermitteln.


UPDATE:
Das große Puzzleteil, das mir fehlte (nicht direkt in den Antworten angegeben - zumindest nicht zum Zeitpunkt des Schreibens), ist, dass Sie Folgendes tun:

var john: Person?

das bedeutet NICHT, dass "john vom Typ Person ist und es könnte null sein", wie ich ursprünglich dachte. Ich habe einfach falsch verstanden, dass Person und Person? völlig unterschiedliche Typen sind. Als ich das begriff, machten all die anderen ?, ! Wahnsinn und die großartigen Antworten unten viel mehr Sinn.

511
Troy

Was bedeutet es, die Instanz zu "entpacken"? Warum ist es notwendig?

Soweit ich kann (das ist auch für mich sehr neu) ...

Der Begriff "verpackt" impliziert, dass wir uns eine optionale Variable als Geschenk in glänzendem Papier vorstellen sollten , das (leider!) Leer sein könnte .

Wenn "umbrochen", ist der Wert einer optionalen Variablen eine Aufzählung mit zwei möglichen Werten (ein bisschen wie ein Boolescher Wert). Diese Aufzählung beschreibt, ob die Variable einen Wert enthält (Some(T)) oder nicht (None).

Wenn es einen Wert gibt, kann dieser durch "Auspacken" der Variablen erhalten werden (Erhalt der T von Some(T)).

Wie unterscheidet sich john!.apartment = number73 von john.apartment = number73? (Umschrieben)

Wenn Sie den Namen einer optionalen Variablen schreiben (z. B. Text john, ohne den !), bezieht sich dies auf die "umbrochene" Aufzählung (Some/None), nicht auf den Wert selbst (T). Daher ist john keine Instanz von Person, und es gibt kein apartment -Mitglied:

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

Der tatsächliche Person -Wert kann auf verschiedene Arten entpackt werden:

  • "erzwungenes Auspacken": john! (gibt den Wert Person zurück, falls vorhanden, Laufzeitfehler, falls nicht)
  • "optionale Bindung": if let p = john { println(p) } (führt das println aus, wenn der Wert existiert)
  • "optionale Verkettung": john?.learnAboutSwift() (führt diese erfundene Methode aus, wenn der Wert existiert)

Ich nehme an, Sie wählen einen dieser Wege zum Auspacken, je nachdem, was im Null-Fall passieren soll und wie wahrscheinlich das ist. Dieser Sprachentwurf erzwingt die explizite Behandlung des Null-Falls, was meiner Meinung nach die Sicherheit gegenüber Obj-C verbessert (wo man leicht vergisst, den Null-Fall zu behandeln).

Update :

Das Ausrufezeichen wird auch in der Syntax für die Deklaration von "Implicitly Unwrapped Optionals" verwendet.

In den bisherigen Beispielen wurde die Variable john als var john:Person? deklariert und ist optional. Wenn Sie den tatsächlichen Wert dieser Variablen möchten, müssen Sie ihn mit einer der drei oben genannten Methoden auspacken.

Wenn es stattdessen als var john:Person! deklariert würde, wäre die Variable ein implizit entpacktes optionales Element (siehe den Abschnitt mit dieser Überschrift in Apples Buch). Beim Zugriff auf den Wert muss diese Art von Variable nicht entpackt werden, und john kann ohne zusätzliche Syntax verwendet werden. Aber Apples Buch sagt:

Implizit ausgepackte Optionen sollten nicht verwendet werden, wenn die Möglichkeit besteht, dass eine Variable zu einem späteren Zeitpunkt null wird. Verwenden Sie immer einen normalen optionalen Typ, wenn Sie während der Lebensdauer einer Variablen nach einem Nullwert suchen müssen.

Update 2 :

Der Artikel " Interesting Swift Features " von Mike Ash gibt Motivation für optionale Typen. Ich finde es toll, klar zu schreiben.

Update 3 :

Ein weiterer nützlicher Artikel über die implizit ausgepackte optionale Verwendung für das Ausrufezeichen: " Swift and the Last Mile " von Chris Adamson. Der Artikel erklärt, dass dies eine pragmatische Maßnahme von Apple ist, mit der die von ihren Objective-C-Frameworks verwendeten Typen deklariert werden, die möglicherweise Null enthalten. Das Deklarieren eines Typs als optional (unter Verwendung von ?) oder implizit entpackt (unter Verwendung von !) ist ein Kompromiss zwischen Sicherheit und Bequemlichkeit. In den im Artikel angegebenen Beispielen hat Apple die Typen als implizit entpackt deklariert, wodurch der aufrufende Code bequemer, aber weniger sicher ist.

Vielleicht könnte Apple in Zukunft ihre Frameworks durchforsten, die Unsicherheit implizit entpackter ("wahrscheinlich nie null") Parameter beseitigen und sie durch optionale ersetzen ("sicherlich könnte insbesondere null sein [hoffentlich dokumentiert!] Umstände ") oder nicht optionale Standarddeklarationen (" ist nie null "), basierend auf dem genauen Verhalten ihres Objective-C-Codes.

519
Ashley

Ich denke, das ist der Unterschied:

var john: Person?

Bedeutet, dass John Null sein kann

john?.apartment = number73

Der Compiler interpretiert diese Zeile als:

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

Während

john!.apartment = number73

Der Compiler interpretiert diese Zeile folgendermaßen:

john.apartment = number73

Daher mit! wird die if-Anweisung entpacken und schneller laufen lassen, aber wenn john gleich nil ist, tritt ein Laufzeitfehler auf.

Ein Zeilenumbruch bedeutet hier also nicht, dass der Speicher umbrochen wird, sondern, dass der Code umbrochen wird. In diesem Fall wird er mit einer if-Anweisung umbrochen, und da Apple die Leistung in der Laufzeit genauestens berücksichtigen soll Damit Sie Ihre App mit der bestmöglichen Leistung ausführen können.

pdate:

Als ich nach 4 Jahren auf diese Antwort zurückkam, da ich in Stackoverflow den höchsten Ruf hatte, habe ich die damalige Bedeutung des Auspackens ein wenig missverstanden. Jetzt, nach 4 Jahren, glaube ich, besteht die Bedeutung des Entpackens darin, den Code von seiner ursprünglichen kompakten Form zu erweitern. Es bedeutet auch, die Unbestimmtheit um dieses Objekt herum zu beseitigen, da wir uns nicht sicher sind, ob es null ist oder nicht. Denken Sie genau wie die Antwort von Ashley darüber an ein Geschenk, das nichts enthalten könnte. Aber ich denke immer noch, dass das Entpacken das Entpacken von Code und nicht das speicherbasierte Entpacken unter Verwendung von Enum ist.

127
Amr

TL; DR

Was bedeutet ein Ausrufezeichen in der Sprache Swift?

Das Ausrufezeichen besagt effektiv: „Ich weiß, dass dieses optionale Element definitiv einen Wert hat. Bitte benutze es. "Dies wird als erzwungenes Auspacken des optionalen Werts bezeichnet:

Beispiel

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

Quelle: https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//Apple_ref/doc/uid/TP40014097-CH5-XID_399

65
Alex Nolasco

Wenn John eine optionale Var wäre (so deklariert)

var john: Person?

dann wäre es für john möglich, keinen wert zu haben (in objc-sprache null wert)

Das Ausrufezeichen sagt dem Compiler im Wesentlichen: "Ich weiß, dass dies ein Wert ist, den Sie nicht testen müssen". Wenn Sie es nicht verwenden möchten, können Sie es unter bestimmten Bedingungen testen:

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

Das Innere wird nur ausgewertet, wenn John einen Wert hat.

37
Ben Gottlieb

john ist ein optionales var. Kann also einen nil -Wert enthalten. Verwenden Sie am Ende des Namens var einen !, um sicherzustellen, dass der Wert nicht null ist.

Aus der Dokumentation

"Wenn Sie sicher sind, dass das optionale Element einen Wert enthält, können Sie auf den zugrunde liegenden Wert zugreifen, indem Sie ein Ausrufezeichen (!) Am Ende des optionalen Namens einfügen. Das Ausrufezeichen besagt effektiv:" Das weiß ich Diese Option hat definitiv einen Wert, bitte verwenden Sie ihn. ”

Eine andere Möglichkeit, einen Nicht-Null-Wert zu überprüfen, ist

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

Hier sind einige Beispiele:

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

Wobei Word ein optionaler Wert ist. bedeutet, dass es einen Wert enthalten kann oder nicht.

Word = name 

Hier hat name einen Wert, damit wir ihn zuweisen können

var cow:String = nil
var dog:String!

Wenn dog zwangsweise entpackt wird, bedeutet dies, dass es einen Wert enthalten muss

dog = cow

Die Anwendung stürzt ab, weil wir nil dem Unwrapped zuweisen

16

In diesem Fall...

var John: Person!

das bedeutet, dass John anfangs keinen Wert hat, dass er gesetzt wird und dass er, sobald er gesetzt ist, nie wieder auf Null gesetzt wird. Aus Bequemlichkeitsgründen kann ich die einfachere Syntax für den Zugriff auf eine optionale Variable verwenden, da dies eine "implizit ausgepackte Option" ist.

15
guest

Wenn Sie aus einer Sprache der C-Familie stammen, werden Sie denken, "Zeiger auf Objekt vom Typ X, das die Speicheradresse 0 (NULL) sein könnte", und wenn Sie aus einer dynamisch getippten Sprache stammen, werden Sie Denken "Objekt, das wahrscheinlich vom Typ X ist, aber möglicherweise vom Typ undefiniert ist". Keines davon ist richtig, obwohl das erste auf Umwegen in der Nähe liegt.

Die Art, wie Sie darüber denken sollten, ist, als wäre es ein Objekt wie:

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

Wenn Sie Ihren optionalen Wert mit foo == nil testen, wird foo.isNil zurückgegeben, und wenn Sie foo! sagen, wird foo.realObject mit der Behauptung foo.isNil == false zurückgegeben. Es ist wichtig, dies zu beachten, denn wenn foo tatsächlich Null ist, wenn Sie foo! ausführen, ist dies ein Laufzeitfehler. Daher möchten Sie in der Regel stattdessen eine bedingte let verwenden, es sei denn, Sie sind sich sehr sicher, dass der Wert Null ist nicht gleich Null sein. Diese Art von Trick bedeutet, dass die Sprache stark typisiert werden kann, ohne dass Sie testen müssen, ob Werte überall gleich Null sind.

In der Praxis verhält es sich nicht wirklich so, weil die Arbeit vom Compiler erledigt wird. Auf einer hohen Ebene gibt es einen Typ Foo?, der von Foo getrennt ist, und der verhindert, dass Funktionen, die den Typ Foo akzeptieren, einen Nullwert empfangen, auf einer niedrigen Ebene jedoch einen optionalen Wert nicht 't ein echtes Objekt, weil es keine Eigenschaften oder Methoden hat; Es ist wahrscheinlich, dass es sich tatsächlich um einen Zeiger handelt, der beim erzwungenen Entpacken mit dem entsprechenden Test NULL (0) sein kann.

In einer anderen Situation, in der ein Ausrufezeichen angezeigt wird, handelt es sich um einen Typ wie in:

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

Dies entspricht in etwa dem Akzeptieren eines optionalen Produkts mit erzwungener Abwicklung, d.h.

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

Sie können dies verwenden, um eine Methode zu haben, die einen optionalen Wert technisch akzeptiert, aber einen Laufzeitfehler aufweist, wenn er null ist. In der aktuellen Version von Swift umgeht dies anscheinend die Nicht-Null-Behauptung, sodass stattdessen ein Fehler auf niedriger Ebene angezeigt wird. Im Allgemeinen keine gute Idee, aber es kann nützlich sein, wenn Sie Code aus einer anderen Sprache konvertieren.

4
Jim Driscoll

Wenn Sie mit C # vertraut sind, entspricht dies nullbaren Typen, die ebenfalls mit einem Fragezeichen deklariert werden:

Person? thisPerson;

In diesem Fall entspricht das Ausrufezeichen dem Zugriff auf die Eigenschaft .Value des Typs nullable wie folgt:

thisPerson.Value
3
Abdurrahman

Das ! bedeutet, dass Sie das Objekt zwangsweise auspacken! folgt. Weitere Informationen finden Sie in der Dokumentation zu Apples, die hier zu finden ist: https://developer.Apple.com/library/ios/documentation/Swift/conceptual/Swift_Programming_Language/TheBasics.html

In Objective C waren Variablen ohne Wert gleich 'nil' (es war auch möglich, 'nil' Werte wie 0 und false zu verwenden), daher war es möglich, Variablen in bedingten Anweisungen zu verwenden (Variablen mit Werten wie 'TRUE') 'und diejenigen ohne Werte waren gleich' FALSE ').

Swift bietet Typensicherheit durch Angabe eines optionalen Werts. d.h. es wird verhindert, dass Fehler beim Zuweisen von Variablen unterschiedlicher Typen gebildet werden.

In Swift können daher nur Boolesche Werte für bedingte Anweisungen angegeben werden.

var hw = "Hello World"

Obwohl 'hw' ein String ist, kann er hier nicht in einer if-Anweisung wie in Objective C verwendet werden.

//This is an error

if hw

 {..}

Dafür muss es erstellt werden als,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}
2
Gokul

Kurz (!): Nachdem Sie eine Variable deklariert haben und sicher sind, dass die Variable einen Wert enthält.

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

andernfalls müssten Sie dies bei jedem Wert nach der Übergabe tun ...

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

Das ! Am Ende eines Objekts steht, dass das Objekt ein optionales Objekt ist und auszupacken ist, wenn es andernfalls einen Nullwert zurückgeben kann. Dies wird oft verwendet, um Fehler abzufangen, die sonst zum Absturz des Programms führen würden.

2
cheborneck

Eine optionale Variable kann einen Wert enthalten oder nicht

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

fall 2: var myVar:String? = nil

wenn Sie jetzt myVar !, fragen, teilen Sie dem Compiler mit, dass er einen Wert in Fall 1 zurückgeben soll, wird "Something" zurückgegeben.

in Fall 2 wird es abstürzen.

Bedeutung! mark zwingt den Compiler, einen Wert zurückzugeben, auch wenn dieser nicht vorhanden ist. Deshalb der Name Force Unwrapping.

1
Ashish Pisey

Wenn Sie es als optional verwenden, packt es das optionale Element aus und überprüft, ob etwas vorhanden ist. Wenn Sie es in einer if-else-Anweisung verwenden, lautet der Code für NOT. Zum Beispiel,

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

Einfach ausgedrückt bedeuten Ausrufezeichen, dass ein optionales Element ausgepackt wird. Ein optionales Element ist eine Variable, die einen Wert haben kann oder nicht. Sie können also überprüfen, ob die Variable leer ist, indem Sie eine if let-Anweisung wie hier gezeigt verwenden und dann das Entpacken erzwingen. Wenn Sie das Entpacken einer leeren Option erzwingen, stürzt Ihr Programm ab. Seien Sie also vorsichtig! Optionals werden durch Setzen eines Fragezeichens am Ende einer expliziten Zuweisung zu einer Variablen deklariert, zum Beispiel könnte ich schreiben:

var optionalExample: String?

Diese Variable hat keinen Wert. Wenn ich es entpacken würde, würde das Programm abstürzen und Xcode würde Ihnen mitteilen, dass Sie versucht haben, ein optionales Element mit dem Wert Null zu entpacken.

Hoffe das hat geholfen.

1
brimstone

IN EINFACHEN WORTEN

SING-Ausrufezeichen gibt an, dass die Variable einen Wert ungleich Null enthalten muss (niemals Null)

1

Die gesamte Geschichte beginnt mit einer Funktion von Swift, die als optionale Variablen bezeichnet wird. Dies sind die Variablen, die einen Wert haben oder keinen Wert haben können. Im Allgemeinen erlaubt uns Swift nicht, eine Variable zu verwenden, die nicht initialisiert ist, da dies zu Abstürzen oder unerwarteten Gründen führen kann und außerdem einen Platzhalter für Hintertüren bereitstellt. Um eine Variable zu deklarieren, deren Wert anfänglich nicht bestimmt wurde, verwenden wir ein '?'. Wenn eine solche Variable deklariert wird, um sie als Teil eines Ausdrucks zu verwenden, muss man sie vor der Verwendung auspacken. Das Auspacken ist eine Operation, durch die der Wert einer Variablen ermittelt wird. Dies gilt für Objekte. Wenn Sie versuchen, sie zu verwenden, wird beim Kompilieren ein Fehler auftreten, wenn Sie sie nicht auspacken. Um eine Variable zu entpacken, die eine optionale Variable ist, muss das Ausrufezeichen "!" wird genutzt.

Es gibt Zeiten, in denen Sie wissen, dass solchen optionalen Variablen Werte beispielsweise vom System oder von Ihrem eigenen Programm zugewiesen werden, aber einige Zeit später, beispielsweise von UI-Outlets, in einer solchen Situation, anstatt eine optionale Variable mit einem Fragezeichen "?" wir gebrauchen "!".

Somit weiß das System, dass diese Variable, die mit "!" ist momentan optional und hat keinen Wert, wird aber später in seinem Leben einen Wert erhalten.

Das Ausrufezeichen enthält also zwei verschiedene Verwendungen: 1. Eine Variable deklarieren, die optional ist und erst später einen Wert erhält. 2. Eine optionale Variable auspacken, bevor sie in einem Ausdruck verwendet wird.

Die obigen Beschreibungen vermeiden zu viel technisches Zeug, hoffe ich.

1

John ist eine optionale Person, dh sie kann einen Wert enthalten oder null sein.

john.apartment = number73

wird verwendet, wenn john nicht optional ist. Da John nie Null ist, können wir sicher sein, dass er Wohnung nicht mit Null bewertet. Während

john!.apartment = number73

verspricht dem Compiler, dass John nicht gleich Null ist, packt dann die Option aus, um Johns Wert abzurufen, und greift auf Johns Wohnungseigentum zu. Verwenden Sie dies, wenn Sie wissen, dass John nicht gleich Null ist. Wenn Sie diese Option auf nil angeben, wird ein Laufzeitfehler angezeigt.

Die Dokumentation enthält ein gutes Beispiel für die Verwendung dieses Befehls, wobei convertNumber optional ist.

if convertedNumber {
    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}
1
Connor
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
0
jeff ayan