73 votes

Interpolation de chaîne Swift 3 incorrecte avec des options implicitement non enveloppées

Pourquoi sont implicitement déballé options non déballé lors de l'utilisation chaîne d'interpolation dans Swift 3?

Exemple: Exécutant le code suivant dans la cour de récréation

var str: String!
str = "Hello"

print("The following should not be printed as an optional: \(str)")

produit de cette sortie:

The following should not be printed as an optional: Optional("Hello")

Bien sûr, je peux concaténer des chaînes de caractères avec l' + de l'opérateur, mais je suis l'aide de la chaîne d'interpolation peu partout dans mon application qui maintenant ne fonctionne plus pour cette raison (bug?).

Est-ce encore un bug ou ont-ils intentionnellement changer ce comportement avec Swift 3?

71voto

Hamish Points 42073

Que par SOI-0054, ImplicitlyUnwrappedOptional<T> n'est plus un type distinct; il n'est qu' Optional<T> maintenant.

Les déclarations sont encore autorisés à être annoté comme implicitement déballé options T!, mais cela ajoute un attribut caché à informer le compilateur que leur valeur peut être la force déballé dans des contextes qui exigent de leurs déballé type T; leur type réel est maintenant T?.

Ainsi, vous pouvez penser de cette déclaration:

var str: String!

effectivement ressembler à ceci:

@_implicitlyUnwrapped // this attribute name is fictitious 
var str: String?

Seul le compilateur voit ce @_implicitlyUnwrapped d'attribut, mais ce qu'il permet pour est implicite déballage de la strs'valeur dans des contextes qui demande un String (non déballé):

// `str` cannot be type-checked as a strong optional, so the compiler will implicitly
// force unwrap it (causing a crash in this case)
let x: String = str

// We're accessing a member on the unwrapped type of `str`, so it'll also be implicitly
// force unwrapped here
print(str.count)

Mais dans tous les autres cas où l' str peut être cochée qu'une forte facultatif, ce sera:

// x is inferred to be a String? (because we really are assigning a String?)
let x = str 

// str is implicitly coerced from String? to Any
let y: Any = str

Et le compilateur préférera toujours la considérer comme tel sur la force de déballage.

Comme la proposition dit (l'emphase est mienne):

Si l'expression peut être explicitement type vérifié avec une forte option type, il sera. Cependant, le type de vérificateur de tomber en arrière pour forcer l'option si nécessaire. L'effet de ce comportement est que le résultat d'une expression qui se réfère à une valeur déclarée T! sera soit de type T ou de type T?.

Quand il s'agit de la chaîne d'interpolation, sous le capot, le compilateur utilise cette initialiser à partir de l' _ExpressibleByStringInterpolation protocole pour évaluer une chaîne d'interpolation segment:

/// Creates an instance containing the appropriate representation for the
/// given value.
///
/// Do not call this initializer directly. It is used by the compiler for
/// each string interpolation segment when you use string interpolation. For
/// example:
///
///     let s = "\(5) x \(2) = \(5 * 2)"
///     print(s)
///     // Prints "5 x 2 = 10"
///
/// This initializer is called five times when processing the string literal
/// in the example above; once each for the following: the integer `5`, the
/// string `" x "`, the integer `2`, the string `" = "`, and the result of
/// the expression `5 * 2`.
///
/// - Parameter expr: The expression to represent.
init<T>(stringInterpolationSegment expr: T)

Par conséquent, lorsque implicitement appelé par votre code:

var str: String!
str = "Hello"

print("The following should not be printed as an optional: \(str)")

En tant que strs'type réel est - String?, par défaut qu'est ce que le compilateur déduit le générique de l'espace réservé T . Par conséquent, la valeur de str ne sera pas en vigueur déballé, et vous finirez par voir la description facultative.

Si vous le souhaitez pour un IUO de force déballé quand utilisé dans la chaîne de l'interpolation, vous pouvez simplement utiliser la force de déballer l'opérateur !:

var str: String!
str = "Hello"

print("The following should not be printed as an optional: \(str!)")

ou vous pouvez forcer à sa non-type facultatif (dans ce cas - String) afin de forcer le compilateur à implicitement force déballer pour vous:

print("The following should not be printed as an optional: \(str as String)")

tous deux, bien sûr, va planter si str est nil.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X