swift - the - ¿Cómo evitar que la fuerza desenvuelva una variable?
swift(lenguaje de programación) (5)
Antes de desenvolver una variable opcional, debe verificar si es
nil
contrario, su aplicación se bloqueará si la variable contiene
nil
.
Y los controles se pueden realizar de varias maneras, como:
-
if let
-
guard
-
if-else
- utilizando operador ternario
- Operador de fusión nula
Y cuál usar completamente depende del requisito.
Puedes reemplazar este código
if middleName == nil {
return "/(firstName) /(lastName)"
}else{
return "/(firstName) /(middleName!) /(lastName)"
}
por
return "/(firstName)/(middleName != nil ? " /(middleName!) " : " " )/(lastName)"
O
también puede usar el operador de fusión nulo (a ?? b) desenvuelve un a opcional si contiene un valor, o devuelve un valor predeterminado b si a es nulo.
¿Cómo evito usar el! La operación de desenrollado forzado ya que usar esto suele ser una mala opción.
¿Cuál es la mejor opción con código como el siguiente donde usarlo hace que el código se vea más simple y debido a la marca if, verifique la variable! se llama nunca será nulo y, por lo tanto, no puede bloquearse.
Mi instructor nos presentó al operador bang (!) Y luego nos dijo que nunca lo volviéramos a usar. Diciéndonos por qué, por supuesto, que bloqueará nuestra aplicación si la opción opcional es nula.
Sin embargo, me encuentro en situaciones como estas en las que el operador de explosión parece ser la opción más concisa y segura.
func fullName() -> String {
if middleName == nil {
return "/(firstName) /(lastName)"
}else{
return "/(firstName) /(middleName!) /(lastName)"
}
}
¿Hay una mejor manera de hacer algo como esto?
Además, aquí está la clase completa si alguien se pregunta.
class CPerson{
var firstName: String
var middleName: String?
var lastName: String
init(firstName: String, middleName: String?, lastName: String) {
self.firstName = firstName
self.middleName = middleName
self.lastName = lastName
}
convenience init(firstName: String, lastName: String) {
self.init(firstName: firstName, middleName: nil, lastName: lastName)
}
func fullName() -> String {
if middleName == nil {
return "/(firstName) /(lastName)"
}else{
return "/(firstName) /(middleName!) /(lastName)"
}
}
}
Mi instructor dijo "Si te veo usando el operador de explosión, vamos a pelear" O_O
En este caso, su instructor está equivocado. Tu función es absolutamente segura. middleName no cambiará de no nulo a nulo a sus espaldas. Su función puede fallar si comete un error de ortografía y escribe el nombre de una variable diferente en lugar de middleName, pero de todos modos eso sería un error y el bloqueo lo llevaría al error.
Pero generalmente "if let ..." es la mejor manera de manejar esto, porque combina la prueba y el desenvolvimiento.
También hay situaciones en las que no dice "si es nulo, se bloqueará, eso es malo", sino "si es nulo, entonces quiero que se bloquee" (generalmente porque sabe que solo puede ser nulo si hay un error en alguna parte en tu código). En ese caso ! hace exactamente lo que quieres
Lo que hiciste funcionará y, de hecho, una vez que sepas que no es nulo, ¡usa! es una forma correcta de forzarlo a desenvolverlo.
Sin embargo, Swift tiene una función llamada Enlace opcional ( https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html ).
En su caso sería así:
func fullName() -> String {
if let middle = middleName {
return "/(firstName) /(middleName) /(lastName)"
} else {
return "/(firstName) /(lastName)"
}
}
Lo que hace el enlace opcional es, como dice Apple en el enlace anterior, "Usted usa el enlace opcional para averiguar si un opcional contiene un valor y, de ser así, hacer que ese valor esté disponible como una constante o variable temporal".
Entonces, dentro de sus corchetes, tiene acceso al
middle
y puede usarlo como un no conocido.
También puede encadenarlos para tener acceso a múltiples constantes temporales y no necesita encadenar sentencias if.
E incluso puede usar una cláusula
where
para evaluar una condición opcional.
De nuevo de los documentos de Apple anteriores:
if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber {
print("/(firstNumber) < /(secondNumber)")
}
Su instructor es, en términos generales, correcto. Definitivamente en este caso. No hay razón para hacer este caso tan especial y forzar el código duplicado.
func fullName() -> String {
return [firstName, middleName, lastName] // The components
.flatMap{$0} // Remove any that are nil
.joined(separator: " ") // Join them up
}
Esto solo une todas las partes no nulas del nombre con espacios. Las otras respuestas aquí también están bien, pero no se escalan tan bien como para agregar más piezas opcionales (como un título "Sr." o sufijo "Jr.").
(Esto está en la sintaxis de Swift3. Swift 2 es muy similar, es
joinWithSeparator(_:)
lugar).
Utilice las construcciones
if let
o
guard
:
func fullName() -> String {
if let middleName = middleName {
return "/(firstName) /(middleName) /(lastName)"
} else {
return "/(firstName) /(lastName)"
}
}
func fullName() -> String {
guard let middleName = middleName else {
return "/(firstName) /(lastName)"
}
return "/(firstName) /(middleName) /(lastName)"
}
He puesto la declaración de
guard
para completar, pero como otros han comentado, esto se usa más comúnmente en un caso de error / falla.
También recomendaría no usar la interpolación de cadenas para cadenas.
Ya son cadenas, no es necesario utilizar la
description
de cada nombre en una nueva cadena.
Considere
return firstName + " " + lastName
.
Consulte
Diferencia entre la interpolación de cadenas y el inicializador de cadenas en Swift
para ver los casos en que la interpolación de cadenas podría devolver un resultado inesperado.