Que signifie "déballer l'instance"? Pourquoi est-ce nécessaire?
Autant que je puisse m'entraîner (c'est très nouveau pour moi aussi) ...
Le terme «enveloppé» implique que nous devrions considérer une variable facultative comme un cadeau, enveloppé dans du papier brillant, qui pourrait (malheureusement!) Être vide .
Lorsqu'elle est "encapsulée", la valeur d'une variable facultative est une énumération avec deux valeurs possibles (un peu comme un booléen). Cette énumération décrit si la variable contient une valeur ( Some(T)
) ou non ( None
).
S'il existe une valeur, celle-ci peut être obtenue en "dépliant" la variable (en obtenant la T
de Some(T)
).
En quoi est-ce john!.apartment = number73
différent de john.apartment = number73
? (Paraphrasé)
Si vous écrivez le nom d'une variable facultative (par exemple, du texte john
, sans le !
), cela fait référence à l'énumération "enveloppée" (Some / None), pas à la valeur elle-même (T). Ce john
n'est donc pas une instance de Person
, et il n'a pas de apartment
membre:
john.apartment
// 'Person?' does not have a member named 'apartment'
La Person
valeur réelle peut être dépliée de différentes manières:
- "dépliage forcé":
john!
(donne la Person
valeur si elle existe, erreur d'exécution si elle est nulle)
- "liaison facultative":
if let p = john { println(p) }
(exécute le println
si la valeur existe)
- "chaînage optionnel":
john?.learnAboutSwift()
(exécute cette méthode reconstituée si la valeur existe)
Je suppose que vous choisissez l'une de ces façons de déballer, en fonction de ce qui devrait arriver dans le cas nul et de la probabilité que cela se produise. Cette conception du langage oblige le cas nul à être traité explicitement, ce qui, je suppose, améliore la sécurité par rapport à Obj-C (où il est facile d'oublier de gérer le cas nul).
Mise à jour :
Le point d'exclamation est également utilisé dans la syntaxe pour déclarer les "options implicitement non enveloppées".
Jusqu'à présent, dans les exemples, la john
variable a été déclarée comme var john:Person?
, et il s'agit d'un facultatif. Si vous voulez la valeur réelle de cette variable, vous devez la déballer en utilisant l'une des trois méthodes ci-dessus.
Si elle était déclarée comme à la var john:Person!
place, la variable serait une option implicitement non enveloppée (voir la section avec cette rubrique dans le livre d'Apple). Il n'est pas nécessaire de déballer ce type de variable lors de l'accès à la valeur et john
peut être utilisé sans syntaxe supplémentaire. Mais le livre d'Apple dit:
Les options implicitement non enveloppées ne doivent pas être utilisées lorsqu'il existe une possibilité qu'une variable devienne nulle à un stade ultérieur. Utilisez toujours un type facultatif normal si vous devez rechercher une valeur nulle pendant la durée de vie d'une variable.
Mise à jour 2 :
L'article « Fonctionnalités Swift intéressantes » de Mike Ash donne une certaine motivation pour les types facultatifs. Je pense que c'est une excellente écriture claire.
Mise à jour 3 :
Un autre article utile sur l' utilisation facultative implicitement déballée du point d'exclamation: " Swift and the Last Mile " par Chris Adamson. L'article explique qu'il s'agit d'une mesure pragmatique d'Apple utilisée pour déclarer les types utilisés par leurs frameworks Objective-C qui pourraient contenir zéro. Déclarer un type comme facultatif (en utilisant ?
) ou implicitement déballé (en utilisant !
) est "un compromis entre sécurité et commodité". Dans les exemples donnés dans l'article, Apple a choisi de déclarer les types implicitement déballés, ce qui rend le code d'appel plus pratique, mais moins sûr.
Peut-être qu'Apple pourrait passer en revue leurs cadres à l'avenir, supprimant l'incertitude des paramètres implicitement non emballés ("probablement jamais nuls") et les remplaçant par des paramètres facultatifs ("certainement pourrait être nul en particulier [espérons-le, documenté!] Circonstances") ou standard non -des déclarations optionnelles ("n'est jamais nul"), basées sur le comportement exact de leur code Objective-C.
Voici ce que je pense être la différence:
Signifie que john peut être nul
Le compilateur interprétera cette ligne comme:
Tandis que
Le compilateur interprétera cette ligne simplement:
Par conséquent, en utilisant! déballera l'instruction if et accélérera son exécution, mais si john est nul, une erreur d'exécution se produira.
Donc, boucler ici ne signifie pas qu'il est encapsulé en mémoire, mais cela signifie qu'il est encapsulé dans du code, dans ce cas, il est encapsulé avec une instruction if, et parce qu'Apple prête une attention particulière aux performances lors de l'exécution, ils veulent vous donner un moyen de faites fonctionner votre application avec les meilleures performances possibles.
Mise à jour:
Pour en revenir à cette réponse après 4 ans, car j'ai obtenu la réputation la plus élevée dans Stackoverflow :) J'ai mal compris un peu le sens du déballage à ce moment-là. Maintenant, après 4 ans, je crois que le sens du déballage ici est d'étendre le code à partir de sa forme compacte d'origine. Cela signifie également supprimer le flou autour de cet objet, car nous ne sommes pas sûrs par définition qu'il soit nul ou non. Tout comme la réponse d'Ashley ci-dessus, pensez-y comme un cadeau qui ne pourrait rien contenir. Mais je pense toujours que le déballage est un déballage de code et non un débouchage basé sur la mémoire comme utilisant l'énumération.
la source
TL; DR
Que signifie un point d'exclamation dans la langue Swift?
Exemple
Source: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399
la source
let f: String! = "hello"
et puisprint(f)
, la sortie estOptional("hello")
au lieu de juste"hello"
.Si john était une variable facultative (déclarée ainsi)
alors il serait possible que john n'ait aucune valeur (dans le langage ObjC, valeur nulle)
Le point d'exclamation indique essentiellement au compilateur "Je sais que cela a une valeur, vous n'avez pas besoin de la tester". Si vous ne vouliez pas l'utiliser, vous pouvez le tester conditionnellement:
L'intérieur de ceci n'évaluera que si john a une valeur.
la source
“let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.”
Mais cela fonctionne très bien sans! Quelque chose semble étrange ici.John?
et je suis deJohn
deux types différents. L'un est de type Personne facultative et l'autre Type de personne. La personne facultative doit être déballée avant de pouvoir sortir la personne. Mais comme vous le dites, cela semble se produire au moins dans ces circonstances sans avoir à faire quoi que ce soit. Cela semble faire le! redondant. À moins que le ! est TOUJOURS facultatif mais une chose suggérée à faire pour détecter les erreurs de compilation. Un peu comme attribuer des variables / permet à un type particulier peut être explicitelet John: Person = ...
mais peut également être déduitlet John = ...
.Une perspective d'ensemble à ajouter aux autres réponses utiles mais plus centrées sur les détails:
Dans Swift, le point d'exclamation apparaît dans plusieurs contextes:
let name = nameLabel!.text
var logo: UIImageView!
logo.image = thing as! UIImage
try! NSJSONSerialization.JSONObjectWithData(data, [])
Chacun d'eux est une construction de langage différente avec une signification différente, mais ils ont tous trois points importants en commun:
1. Les points d'exclamation contournent les contrôles de sécurité de Swift au moment de la compilation.
Lorsque vous utilisez
!
dans Swift, vous dites essentiellement: «Hé, compilateur, je sais que vous pensez qu'une erreur pourrait se produire ici, mais je sais avec une certitude absolue que cela ne se produira jamais."Tout le code valide ne rentre pas dans la boîte du système de type de compilation de Swift - ou dans la vérification de type statique d' une langue, d'ailleurs. Il existe des situations où vous pouvez prouver logiquement qu'une erreur ne se produira jamais, mais vous ne pouvez pas le prouver au compilateur . C'est pourquoi les concepteurs de Swift ont ajouté ces fonctionnalités en premier lieu.
Cependant, chaque fois que vous utilisez
!
, vous excluez d'avoir un chemin de récupération pour une erreur, ce qui signifie que…2. Les points d'exclamation sont des plantages potentiels.
Un point d'exclamation dit également: "Hé Swift, je suis si certain que cette erreur ne peut jamais se produire qu'il vaut mieux que vous plantiez toute mon application que pour moi de coder un chemin de récupération pour elle."
C'est une affirmation dangereuse. Il peut être le bon: dans le code critique où vous avez bien réfléchi aux invariants de votre code, il se peut que la sortie fausse soit pire qu'un crash.
Cependant, quand je vois
!
à l'état sauvage, il est rarement utilisé avec autant de conscience. Au lieu de cela, cela signifie trop souvent: «cette valeur était facultative et je n'ai pas vraiment réfléchi à la raison pour laquelle elle pourrait être nulle ou à la façon de gérer correctement cette situation, mais en ajoutant!
fait compiler ... donc mon code est correct, non?"Attention à l'arrogance du point d'exclamation. Au lieu…
3. Les points d'exclamation sont mieux utilisés avec parcimonie.
Chacune de ces
!
constructions a une?
contrepartie qui vous oblige à faire face au cas d'erreur / nul:if let name = nameLabel?.text { ... }
var logo: UIImageView?
logo.image = thing as? UIImage
try? NSJSONSerialization.JSONObjectWithData(data, [])
Si vous êtes tenté d'utiliser
!
, il est toujours bon de considérer attentivement pourquoi vous n'utilisez pas à la?
place. Est-ce que planter votre programme est vraiment la meilleure option si l'!
opération échoue? Pourquoi cette valeur est-elle facultative / disponible?Existe-t-il un chemin de récupération raisonnable que votre code pourrait emprunter dans le cas nil / erreur? Si oui, codez-le.
Si cela ne peut pas être nul, si l'erreur ne peut jamais se produire, alors existe-t-il un moyen raisonnable de retravailler votre logique pour que le compilateur le sache? Si oui, faites-le; votre code sera moins sujet aux erreurs.
Il y a des moments où il n'y a aucun moyen raisonnable de gérer une erreur, et simplement ignorer l'erreur - et donc procéder avec des données erronées - serait pire que de planter. Ceux le moment d'utiliser le déballage forcé.
Je recherche périodiquement l'ensemble de ma base de code
!
et vérifie chaque utilisation de celui-ci. Très peu d'utilisations résistent à l'examen. (Au moment de la rédaction de ce document, l'ensemble du framework Siesta en avait exactement deux instances .)Cela ne veut pas dire que vous ne devriez jamais utiliser
!
dans votre code - juste que vous devez l'utiliser en pleine conscience et ne jamais en faire l'option par défaut.la source
func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) }
Étant donné 3. existe-t-il une meilleure façon de l'écrire?func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
john
est une optionvar
. Peut donc contenir unenil
valeur. Pour vous assurer que la valeur n'est pas nulle, utilisez un!
à la fin duvar
nom.De la documentation
«Une fois que vous êtes sûr que l'option contient une valeur, vous pouvez accéder à sa valeur sous-jacente en ajoutant un point d'exclamation (!) À la fin du nom de l'option. Le point d'exclamation indique effectivement: «Je sais que cette option a définitivement une valeur; veuillez l'utiliser. "
Une autre façon de vérifier la valeur non nulle est
la source
john.apartment = number73
dit également "Je sais que cette option a certainement une valeur; veuillez l'utiliser." ...Voici quelques exemples:
Où
word
est une valeur facultative. signifie qu'il peut ou non contenir une valeur.Voici
name
une valeur pour que nous puissions l'attribuerOù
dog
est déplié avec force signifie qu'il doit contenir une valeurL'application se bloquera car nous sommes assignés
nil
à des dépliésla source
var c:Int = nil
obtiendra: "Nil ne peut pas initialiser le type spécifié 'int'"Dans ce cas...
var John: Personne!
cela signifie qu'au départ, John aura une valeur nulle, elle sera définie et une fois définie, elle ne sera plus jamais dirigée par zéro. Par conséquent, pour plus de commodité, je peux utiliser la syntaxe la plus simple pour accéder à une variable facultative, car il s'agit d'une «option implicitement non enveloppée»
la source
Si vous venez d'un langage de la famille C, vous penserez "pointeur vers un objet de type X qui pourrait être l'adresse mémoire 0 (NULL)", et si vous venez d'un langage typé dynamiquement vous serez penser "Objet qui est probablement de type X mais qui pourrait être de type non défini". Aucun de ces éléments n'est en fait correct, bien que d'une manière détournée, le premier soit proche.
La façon dont vous devriez y penser est comme si c'était un objet comme:
Lorsque vous testez votre valeur facultative avec
foo == nil
elle revient vraimentfoo.isNil
, et lorsque vous ditesfoo!
qu'elle revientfoo.realObject
avec une affirmationfoo.isNil == false
. Il est important de le noter car si enfoo
fait il est nulfoo!
, c'est une erreur d'exécution, donc vous voudrez généralement utiliser un let conditionnel à la place, sauf si vous êtes très sûr que la valeur ne sera pas nulle. Ce genre de ruse signifie que la langue peut être fortement typée sans vous forcer à tester si les valeurs sont nulles partout.En pratique, cela ne se comporte pas vraiment comme ça car le travail est fait par le compilateur. À un niveau élevé, il existe un type
Foo?
distinct deFoo
celui qui empêche les fonctions acceptant le typeFoo
de recevoir une valeur nulle, mais à un niveau bas, une valeur facultative n'est pas un véritable objet car elle n'a pas de propriétés ou de méthodes; il est probable qu'en fait c'est un pointeur qui peut être NULL (0) avec le test approprié lors du déballage forcé.Il existe une autre situation dans laquelle vous verriez un point d'exclamation sur un type, comme dans:
Cela équivaut à peu près à accepter une option avec un déballage forcé, c'est-à-dire:
Vous pouvez l'utiliser pour avoir une méthode qui accepte techniquement une valeur facultative mais qui aura une erreur d'exécution si elle est nulle. Dans la version actuelle de Swift, cela contourne apparemment l'assertion is-not-nil, vous aurez donc une erreur de bas niveau à la place. Ce n'est généralement pas une bonne idée, mais cela peut être utile lors de la conversion de code à partir d'une autre langue.
la source
Le ! signifie que vous forcez le déballage de l'objet! suit. Plus d'informations peuvent être trouvées dans la documentation Apples, qui peut être trouvée ici: https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/TheBasics.html
la source
Si vous connaissez C #, cela ressemble à des types Nullable qui sont également déclarés à l'aide d'un point d'interrogation:
Et le point d'exclamation dans ce cas équivaut à accéder à la propriété .Value du type nullable comme ceci:
la source
Dans l'objectif C, les variables sans valeur étaient égales à «nil» (il était également possible d'utiliser des valeurs «nil» identiques à 0 et fausses), d'où la possibilité d'utiliser des variables dans les instructions conditionnelles (les variables ayant des valeurs sont identiques à «TRUE» »et ceux sans valeur étaient égaux à« FAUX »).
Swift assure la sécurité du type en fournissant une «valeur facultative». c'est-à-dire qu'il empêche les erreurs formées d'affecter des variables de différents types.
Ainsi, dans Swift, seuls les booléens peuvent être fournis sur des instructions conditionnelles.
Ici, même si «hw» est une chaîne, elle ne peut pas être utilisée dans une instruction if comme dans l'objectif C.
Pour cela, il doit être créé comme,
la source
Le ! à la fin d'un objet dit que l'objet est facultatif et à déballer s'il peut sinon retourner un néant. Ceci est souvent utilisé pour intercepter les erreurs qui pourraient autrement planter le programme.
la source
En bref (!): Une fois que vous avez déclaré une variable et que vous êtes certain que la variable contient une valeur.
sinon, vous devriez le faire à chaque fois que vous avez passé une valeur ...
la source
John est une personne facultative, ce qui signifie qu'elle peut contenir une valeur ou être nulle.
est utilisé si john n'est pas facultatif. Puisque john n'est jamais nul, nous pouvons être sûrs qu'il n'appellera pas apartment sur une valeur nulle. Tandis que
promet au compilateur que john n'est pas nul, puis déballe l'option pour obtenir la valeur de john et accède à la propriété de l'appartement de john. Utilisez ceci si vous savez que john n'est pas nul. Si vous appelez cela sur une option nil, vous obtiendrez une erreur d'exécution.
La documentation comprend un bel exemple d'utilisation de ceci où convertNumber est facultatif.
la source
john.apartment = number73
, cela ne donnera pas lieu à une erreur à moins que je mette un '!' après john?john
option ne dise pas au compilateur que j'ai besoin qu'il soit non nul? ... Et dans votrevar jack: Person = john!
exemple, le manque d'un? après que personne ait dit au compilateur que vous devezjohn
être non nul? Dans l'ensemble, le!
semble semble un peu redondant ... J'ai toujours l'impression que je manque quelque chose sur la partie "pourquoi" de!
...Pour le dire simplement, les points d'exclamation signifient qu'une option est en cours de déballage. Une option est une variable qui peut avoir une valeur ou non - vous pouvez donc vérifier si la variable est vide, en utilisant une instruction if let comme indiqué ici , puis forcer le déballage. Si vous forcez le déballage d'une option qui est vide, votre programme se bloquera, alors soyez prudent! Les options sont déclarées en mettant un point d'interrogation à la fin d'une affectation explicite à une variable, par exemple je pourrais écrire:
Cette variable n'a aucune valeur. Si je devais le déballer, le programme planterait et Xcode vous dirait que vous avez essayé de déballer une option avec une valeur nulle.
J'espère que cela a aidé.
la source
EN MOTS SIMPLES
UTILISATION Le point d'exclamation indique que la variable doit être constituée d'une valeur non nulle (elle ne doit jamais être nulle)
la source
L'histoire entière commence par une fonctionnalité de vars rapides appelés optionnels. Ce sont les vars qui peuvent avoir une valeur ou non. En général, swift ne nous permet pas d'utiliser une variable qui n'est pas initialisée, car cela peut entraîner des plantages ou des raisons inattendues et également servir un espace réservé pour les backdoors. Ainsi, pour déclarer une variable dont la valeur n'est pas initialement déterminée, nous utilisons un «?». Lorsqu'une telle variable est déclarée, pour l'utiliser comme partie d'une expression, il faut les déballer avant de l'utiliser, le déballage est une opération par laquelle la valeur d'une variable est découverte, cela s'applique aux objets. Sans déballer si vous essayez de les utiliser, vous aurez une erreur de temps de compilation. Pour déballer une variable qui est une variable facultative, point d'exclamation "!" est utilisé.
Il y a maintenant des moments où vous savez que de telles variables facultatives se verront attribuer des valeurs par le système par exemple ou votre propre programme, mais un peu plus tard, par exemple les sorties d'interface utilisateur, dans une telle situation au lieu de déclarer une variable facultative à l'aide d'un point d'interrogation "?" nous utilisons "!".
Ainsi, le système sait que cette variable qui est déclarée avec "!" est facultatif en ce moment et n'a aucune valeur mais recevra une valeur plus tard dans sa vie.
Ainsi, le point d'exclamation possède deux usages différents, 1. Déclarer une variable qui sera facultative et recevra définitivement la valeur 2. Développer une variable facultative avant de l'utiliser dans une expression.
Les descriptions ci-dessus évitent trop de choses techniques, j'espère.
la source
Si vous l'utilisez comme optionnel, il déballe l'option et voit s'il y a quelque chose. Si vous l'utilisez dans une instruction if-else, c'est le code pour NOT. Par exemple,
la source
Une variable facultative peut contenir une valeur ou ne pas l'être
cas 1:
var myVar:String? = "Something"
cas 2:
var myVar:String? = nil
maintenant, si vous demandez à myVar !, vous dites au compilateur de renvoyer une valeur au cas où 1 reviendrait
"Something"
dans le cas 2, il plantera.
Sens ! La marque forcera le compilateur à renvoyer une valeur, même si elle n'est pas là. c'est pourquoi le nom Force Unwrapping .
la source
la source
DEMANDE TOI
person?
a- t- il unapartment
membre / une propriété? OUperson
a- t- il unapartment
membre / une propriété?Si vous ne pouvez pas répondre à cette question, continuez à lire:
Pour comprendre, vous devrez peut-être un niveau super-basique de compréhension des génériques . Voyez ici . Beaucoup de choses dans Swift sont écrites en utilisant des génériques. Optionnels inclus
Le code ci-dessous est disponible à partir de cette vidéo de Stanford . Je vous recommande vivement de regarder les 5 premières minutes
Une option est une énumération avec seulement 2 cas
Reliure optionnelle:
quand vous dites que vous voulez dire
var john: Person?
par exemple:L'énumération ci-dessus a-t-elle une propriété nommée
apartment
? Le voyez-vous quelque part? Ce n'est pas là du tout! Cependant, si vous le déballez, c'est-à-dire,person!
vous pouvez ... ce qu'il fait sous le capot est:Optional<Person>.Some(Person(name: "John Appleseed"))
Si vous aviez défini
var john: Person
au lieu de:var john: Person?
alors vous n’auriez plus eu besoin de l’!
utiliser, carPerson
lui-même a un membre deapartment
Comme une discussion future sur les raisons pour lesquelles l'utilisation
!
de déballer n'est parfois pas recommandée, voir ce Q&Rla source