array - Swift 3 interpolación de cadenas incorrecta con opciones implícitas sin envolver
switch en swift 3 (1)
Según
SE-0054
,
ImplicitlyUnwrappedOptional<T>
ya no es un tipo distinto;
solo hay
Optional<T>
ahora.
Las declaraciones aún se pueden anotar como opciones
T!
implícitamente sin envolver
T!
, pero al hacerlo solo agrega un atributo oculto para informar al compilador que su valor puede ser forzado a desenvolverse en contextos que demandan su tipo
T
sin envolver;
su tipo real es ahora
T?
.
Entonces puedes pensar en esta declaración:
var str: String!
como realmente se ve así:
@_implicitlyUnwrapped // this attribute name is fictitious
var str: String?
Solo el compilador ve este atributo
@_implicitlyUnwrapped
, pero lo que permite es el desenvolvimiento implícito del valor de
str
en contextos que exigen un
String
(su tipo sin envolver):
// `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)
Pero en todos los demás casos en los que
str
puede verificarse como una opción fuerte, será:
// `x` is inferred to be a `String?` (because we really are assigning a `String?`)
let x = str
let y: Any = str // `str` is implicitly coerced from `String?` to `Any`
print(str) // Same as the previous example, as `print` takes an `Any` parameter.
Y el compilador siempre preferirá tratarlo como tal sobre el desenvolvimiento forzado.
Como dice la propuesta (énfasis mío):
Si la expresión puede ser explícitamente marcada con un tipo opcional fuerte, lo será . Sin embargo, el verificador de tipo volverá a forzar el opcional si es necesario. El efecto de este comportamiento es que el resultado de cualquier expresión que se refiere a un valor declarado como
T!
tendrá tipoT
o tipoT?
.
Cuando se trata de la interpolación de cadenas, debajo del capó el compilador usa este inicializador del
protocolo
_ExpressibleByStringInterpolation
para evaluar un segmento de interpolación de cadenas:
/// 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)
Por lo tanto, cuando su código lo llama implícitamente:
var str: String!
str = "Hello"
print("The following should not be printed as an optional: /(str)")
Como el tipo real de
str
es
String?
, de forma predeterminada, eso es lo que el compilador deducirá que es el marcador de posición genérico
T
Por lo tanto, el valor de
str
no se
str
a la fuerza, y terminarás viendo la descripción de una opción.
Si desea que un IUO se desenvuelva a la fuerza cuando se usa en la interpolación de cuerdas, ¡simplemente puede usar el operador de desenrollado forzado
!
:
var str: String!
str = "Hello"
print("The following should not be printed as an optional: /(str!)")
o puede forzar a su tipo no opcional (en este caso,
String
) para forzar al compilador a forzar implícitamente a desenvolverlo para usted:
print("The following should not be printed as an optional: /(str as String)")
ambos, por supuesto, se bloquearán si
str
es
nil
.
¿Por qué los opcionales implícitamente sin envolver no se desenvuelven cuando se usa la interpolación de cadenas en Swift 3?
Ejemplo : ejecutar el siguiente código en el patio de recreo
var str: String!
str = "Hello"
print("The following should not be printed as an optional: /(str)")
produce esta salida:
The following should not be printed as an optional: Optional("Hello")
Por supuesto, puedo concatenar cadenas con el operador
+
, pero estoy usando la interpolación de cadenas prácticamente en todas partes en mi aplicación, que ahora ya no funciona debido a esto (¿error?).
¿Es esto incluso un error o cambiaron intencionalmente este comportamiento con Swift 3?