¿Qué significa un signo de exclamación en el lenguaje Swift?


518

La guía del lenguaje de programación Swift tiene el siguiente ejemplo:

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)

Luego, al asignar el departamento a la persona, usan un signo de exclamación para "desenvolver la instancia":

john!.apartment = number73

¿Qué significa "desenvolver la instancia"? ¿Por qué es necesario? ¿Cómo es diferente de hacer lo siguiente?

john.apartment = number73

Soy muy nuevo en el lenguaje Swift. Solo trato de entender lo básico.


ACTUALIZACIÓN:
La gran pieza del rompecabezas que me faltaba (no se indica directamente en las respuestas, al menos no al momento de escribir esto) es que cuando haces lo siguiente:

var john: Person?

eso NO significa que " johnes de tipo Persony podría ser nulo", como originalmente pensé. Simplemente estaba malinterpretando eso Persony Person?son tipos completamente separados. Una vez que entendí eso, todo lo demás ?, la !locura y las excelentes respuestas a continuación, tenían mucho más sentido.

Respuestas:


530

¿Qué significa "desenvolver la instancia"? ¿Por qué es necesario?

Hasta donde puedo hacer ejercicio (esto también es muy nuevo para mí) ...

El término "envuelto" implica que debemos pensar en una variable Opcional como un regalo, envuelto en papel brillante, que podría (¡lamentablemente!) Estar vacío .

Cuando se "ajusta", el valor de una variable opcional es una enumeración con dos valores posibles (un poco como un booleano). Esta enumeración describe si la variable tiene un valor ( Some(T)) o no ( None).

Si hay un valor, esto puede obtenerse "desenvolviendo" la variable (obteniendo el Tde Some(T)).

¿Cómo es john!.apartment = number73diferente de john.apartment = number73? (Parafraseado)

Si escribe el nombre de una variable Opcional (por ejemplo john, texto , sin el !), esto se refiere a la enumeración "envuelta" (Algunos / Ninguno), no al valor en sí (T). Entonces johnno es una instancia de Person, y no tiene un apartmentmiembro:

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

El Personvalor real se puede desenvolver de varias maneras:

  • "desenvolvimiento forzado": john!(da el Personvalor si existe, error de tiempo de ejecución si es nulo)
  • "enlace opcional": if let p = john { println(p) }(ejecuta printlnel valor si existe)
  • "encadenamiento opcional": john?.learnAboutSwift()(ejecuta este método inventado si el valor existe)

Supongo que eliges una de estas formas de desenvolver, dependiendo de lo que suceda en el caso nulo y de cuán probable sea. Este diseño de lenguaje obliga a que el caso nulo se maneje explícitamente, lo que supongo que mejora la seguridad sobre Obj-C (donde es fácil olvidar manejar el caso nulo).

Actualización :

El signo de exclamación también se usa en la sintaxis para declarar "Opciones implícitas sin envolver".

En los ejemplos hasta ahora, la johnvariable ha sido declarada como var john:Person?, y es una Opcional. Si desea el valor real de esa variable, debe desenvolverla, utilizando uno de los tres métodos anteriores.

Si se declarara como en su var john:Person!lugar, la variable sería una Opcional implícitamente sin envolver (consulte la sección con este encabezado en el libro de Apple). No es necesario desenvolver este tipo de variable al acceder al valor, y johnpuede usarse sin sintaxis adicional. Pero el libro de Apple dice:

Las opciones implícitamente desenvueltas no deben usarse cuando existe la posibilidad de que una variable se vuelva nula en un momento posterior. Utilice siempre un tipo opcional normal si necesita verificar un valor nulo durante la vida útil de una variable.

Actualización 2 :

El artículo " Características interesantes de Swift " de Mike Ash ofrece cierta motivación para los tipos opcionales. Creo que es genial, una escritura clara.

Actualización 3 :

Otro artículo útil sobre el uso opcional implícitamente sin envolver para el signo de exclamación: " Swift and the Last Mile " de Chris Adamson. El artículo explica que esta es una medida pragmática de Apple utilizada para declarar los tipos utilizados por sus marcos Objective-C que pueden contener nulo. Declarar un tipo como opcional (usando ?) o implícitamente sin envolver (usando !) es "una compensación entre seguridad y conveniencia". En los ejemplos dados en el artículo, Apple ha decidido declarar los tipos como implícitamente desenvueltos, haciendo que el código de llamada sea más conveniente, pero menos seguro.

Tal vez Apple podría revisar sus marcos en el futuro, eliminando la incertidumbre de los parámetros implícitamente desenvueltos ("probablemente nunca nulos") y reemplazándolos por opcionales ("ciertamente podría ser nulo en particular [¡con suerte, documentado!] Circunstancias") o no estándar -opcionales ("nunca es nulo"), basadas en el comportamiento exacto de su código Objective-C.


No estoy seguro de esta explicación. Si solo ejecuta el código sin el! Todavía devuelve el valor real. Quizas el ! es para la velocidad?
Richard Washington

OKAY. ¡Entonces los documentos hablan sobre el uso! cuando sabes con seguridad que se puede desenvolver. Pero puede ejecutar el código bien sin él (una cuarta opción para su lista - desenvolvimiento implícito) Y sin verificar primero. Obtiene el valor o nulo si es nulo. Pero si sabes con certeza que no es nulo, ¡úsala! ... pero todavía no puedo ver por qué harías esto.
Richard Washington

2
Hola @RichardWashington: agregué una actualización a mi respuesta que espero aclare algo de esto.
Ashley

La actualización 3 es exactamente lo que estoy buscando. Antes de leerlo, ¡pensé que Apple estaba mintiendo cuando devolvieron algo como NSURLCredential! que en realidad podría ser nulo.
Golden Thumb

Gracias por la fantástica respuesta @Ashley. Después de leer esta respuesta y algunos de los códigos rápidos de ejemplo de Apple, realmente me parece que en esta compensación entre seguridad y productividad, generalmente es mejor estar del lado más seguro. Una excepción notable que he encontrado es cuando Apple usa el desenvolvimiento forzado para los elementos de la interfaz de usuario, lo que tiene sentido porque primero, los elementos de la interfaz de usuario suelen ser opcionales cuando se trata de un guión gráfico (ya que no se les asigna un valor programáticamente), y segundo porque son casi nunca nulo a menos que el controlador de vista que lo contiene sea nulo, en cuyo caso esta discusión es discutible.
Mihir

126

Esto es lo que creo que es la diferencia:

var john: Person?

Significa que John puede ser nulo

john?.apartment = number73

El compilador interpretará esta línea como:

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

Mientras

john!.apartment = number73

El compilador interpretará esta línea simplemente:

john.apartment = number73

Por lo tanto, usando! desenvolverá la instrucción if y hará que se ejecute más rápido, pero si john es nulo, se producirá un error de tiempo de ejecución.

Entonces, envolver aquí no significa que está envuelto en memoria, pero significa que está envuelto en código, en este caso está envuelto con una declaración if, y debido a que Apple presta mucha atención al rendimiento en tiempo de ejecución, quieren darle una forma de haga que su aplicación funcione con el mejor rendimiento posible.

Actualizar:

Volviendo a esta respuesta después de 4 años, ya que obtuve la mayor reputación en Stackoverflow :) No entendí un poco el significado de desenvolver en ese momento. Ahora, después de 4 años, creo que el significado de desenvolver aquí es expandir el código de su forma compacta original. También significa eliminar la vaguedad alrededor de ese objeto, ya que no estamos seguros por definición de que sea nulo o no. Al igual que la respuesta de Ashley anterior, piense en ello como un regalo que no podría contener nada. Pero sigo pensando que el desenvolvimiento es desenvolvimiento de código y no desenvolvimiento basado en memoria como el uso de la enumeración.


99
En mi patio de juegos john.apartment = number73 no se compila, debe especificar john? .Apartment = number73
Chuck Pinkert

2
@ChuckPinkert tiene razón, la cuarta línea debe editarse a john? .Apartment = number73, ¡buena respuesta!
Bruce

john.apartment = number73 da error: valor del tipo opcional 'Persona?' no desenvuelto: ¿querías usar '!' o '?'
Spiderman

44
El desenvolvimiento no tiene nada que ver con el rendimiento de wrt. La "comprobación nula" aún debe realizarse en tiempo de ejecución, la única diferencia es que se generará un error de tiempo de ejecución en caso de que no haya ningún valor en el Opcional.
madidier

67

TL; DR

¿Qué significa un signo de exclamación en el lenguaje Swift?

El signo de exclamación efectivamente dice: “Sé que este opcional definitivamente tiene un valor; por favor úsalo ". Esto se conoce como desenvolvimiento forzado del valor del opcional:

Ejemplo

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

Fuente: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399


11
Su respuesta es excelente porque entiendo lo que está sucediendo ahora. Lo que no entiendo es por qué existen opciones implícitamente sin envolver. ¿Por qué crear algo definido como una cadena opcional implícitamente desenvuelta, en lugar de un tipo de cadena normal? Su uso a partir de entonces es el mismo. ¿Qué me estoy perdiendo?
pachun

Esto ya no parece ser cierto. En una respuesta de Swift 5, si lo hago let f: String! = "hello"y luego print(f), la salida es en Optional("hello")lugar de solo "hello".
numbermaniac

37

Si juan fuera una var opcional (declarada así)

var john: Person?

entonces sería posible que John no tuviera ningún valor (en el lenguaje de ObjC, valor nulo)

El signo de exclamación básicamente le dice al compilador "Sé que esto tiene un valor, no necesita probarlo". Si no desea utilizarlo, puede probarlo condicionalmente:

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

El interior de esto solo evaluará si John tiene un valor.


44
Gracias por la respuesta, ahora entiendo lo que dice el signo de exclamación, todavía estoy tratando de entender por qué ... Dijiste que le dice al compilador "Sé que esto tiene un valor, no necesitas probar eso". ¿Qué me compra cuando el compilador no lo prueba? Sin el signo de exclamación, ¿el compilador arrojará un error (todavía no tengo un entorno en el que pueda probar Swift)? Es el ! ¿100% necesario para todos los vars opcionales? Si es así, ¿por qué Apple se molestó con eso, en lugar de hacerlo solo por la falta de! significa "Sé que esto tiene un valor, no necesita probarlo"?
Troy

"el compilador arrojará un error" - no, todavía funciona bien, devolviendo el valor como se esperaba. No entiendo esto. Es el ! ¿solo por velocidad cuando estás seguro tal vez?
Richard Washington

De hecho, más adelante en los documentos se habla de opciones implícitamente sin envolver usando el siguiente ejemplo: ¡ “let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.” Pero funciona bien con no! Algo parece extraño aquí.
Richard Washington

3
@ RichardWashington Estás confundido por una buena razón! Los ejemplos en los documentos están dejando de lado algunas cosas y son engañosas porque todo lo que hacen es usar println. Aparentemente, hay al menos un par de casos en los que no es necesario desenvolver los opcionales. Una es cuando se usa println. Otra es cuando se usa la interpolación de cadenas. Entonces, ¿quizás println y la interpolación de cadenas se están desenvolviendo debajo de las cubiertas? Tal vez alguien tenga más información sobre esto. Mirar las definiciones del encabezado Xcode6 Beta no me reveló nada sobre esta magia.
mbeaty

Sí, lo entiendo John?y Johnson dos tipos diferentes. Uno es de tipo Persona opcional y el otro Tipo de persona. La persona opcional debe desenvolverse antes de que pueda sacar a la persona. Pero como usted dice, esto parece suceder al menos en estas circunstancias sin tener que hacer nada. Esto parece hacer el! redundante. A menos que el ! SIEMPRE es opcional, pero se sugiere hacer algo para detectar errores de tiempo de compilación. Algo así como asignar vars / lets a un tipo particular puede ser explícito let John: Person = ...pero también se puede inferir let John = ....
Richard Washington

27

Alguna perspectiva general para agregar a las otras respuestas útiles pero más centradas en los detalles:

En Swift, el signo de exclamación aparece en varios contextos:

  • Envoltura forzada: let name = nameLabel!.text
  • Opcionales implícitamente sin envolver: var logo: UIImageView!
  • Fundición forzada: logo.image = thing as! UIImage
  • Excepciones no manejadas: try! NSJSONSerialization.JSONObjectWithData(data, [])

Cada uno de estos es una construcción de lenguaje diferente con un significado diferente, pero todos tienen tres cosas importantes en común:

1. Los signos de exclamación eluden los controles de seguridad en tiempo de compilación de Swift.

Cuando lo usa !en Swift, esencialmente dice: "Oye, compilador, sé que cree que podría ocurrir un error aquí, pero con total certeza que nunca lo hará".

No todo el código válido cabe en la caja del sistema de tipos de tiempo de compilación de Swift, o la comprobación de tipos estáticos de cualquier idioma, para el caso. Hay situaciones en las que puede probar lógicamente que nunca se producirá un error, pero no puede probarlo al compilador . Es por eso que los diseñadores de Swift agregaron estas características en primer lugar.

Sin embargo, cada vez que usa !, descarta tener una ruta de recuperación para un error, lo que significa que ...

2. Los puntos de exclamación son posibles accidentes.

Un signo de exclamación también dice: "Hola Swift, estoy tan seguro de que este error nunca puede ocurrir que es mejor que bloquees toda mi aplicación que codificar una ruta de recuperación para ella".

Esa es una afirmación peligrosa. Se puede ser la correcta: en clave de misión crítica en la que han pensado mucho sobre invariantes de su código, puede ser que la salida falsa es peor que un accidente.

Sin embargo, cuando veo !en la naturaleza, rara vez se usa con tanta atención. En cambio, con demasiada frecuencia significa, "este valor era opcional y realmente no pensé demasiado sobre por qué podría ser nulo o cómo manejar adecuadamente esa situación, pero agregarlo !lo compiló ... así que mi código es correcto, ¿verdad?"

Cuidado con la arrogancia del signo de exclamación. En lugar…

3. Los puntos de exclamación se usan mejor con moderación.

Cada una de estas !construcciones tiene una ?contraparte que te obliga a lidiar con el caso de error / nulo:

  • Desenvoltura condicional: if let name = nameLabel?.text { ... }
  • Opcionales: var logo: UIImageView?
  • Lanzamientos condicionales: logo.image = thing as? UIImage
  • Excepciones sin falla: try? NSJSONSerialization.JSONObjectWithData(data, [])

Si tiene la tentación de usar !, siempre es bueno considerar cuidadosamente por qué no lo está usando ?. ¿Bloquear su programa es realmente la mejor opción si la !operación falla? ¿Por qué ese valor es opcional / no disponible?

¿Existe una ruta de recuperación razonable que su código podría tomar en el caso de nulo / error? Si es así, codifíquelo.

Si no puede ser nulo, si el error nunca puede suceder, ¿hay alguna forma razonable de reelaborar su lógica para que el compilador lo sepa? Si es así, hazlo; su código será menos propenso a errores.

Hay momentos en que no hay una forma razonable de manejar un error, y simplemente ignorar el error, y así proceder con datos incorrectos, sería peor que estrellarse. Esos son los momentos para usar el desenvolvimiento forzado.

Periódicamente busco en toda mi base de código !y audito cada uso del mismo. Muy pocos usos resisten el escrutinio. (Al escribir estas líneas, todo el marco de Siesta tiene exactamente dos instancias de él).

Eso no quiere decir que nunca debe usarlo !en su código, solo que debe usarlo conscientemente y nunca hacerlo la opción predeterminada.


func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) } Dado 3. ¿Hay una mejor manera de escribirlo?
jenson-button-event

Puedes decirfunc isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
rkgibson2

Las marcas de exclamación no eluden ningún control de seguridad. Obtendrá un bloqueo garantizado si el opcional es nulo. Lo opcional siempre está marcado. Es solo una forma muy brutal de hacer un control de seguridad.
gnasher729

@ gnasher729 Como dice la respuesta, elude las verificaciones de seguridad en tiempo de compilación a favor de una falla de tiempo de ejecución segura .
Paul Cantrell

24

johnEs opcional var. Entonces puede ser contiene un nilvalor. Para asegurarse de que el valor no sea nulo, utilice un !al final del varnombre.

De la documentación

“Una vez que esté seguro de que el opcional contiene un valor, puede acceder a su valor subyacente agregando un signo de exclamación (!) Al final del nombre del opcional. El signo de exclamación efectivamente dice: “Sé que este opcional definitivamente tiene un valor; por favor úsalo ".

Otra forma de verificar el valor no nulo es

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

1
Sí, lo había visto en la documentación, pero aún parece innecesario ... ya que, para mí, john.apartment = number73también dice "Sé que este opcional definitivamente tiene un valor; utilícelo" ...
Troy

66
Sí, pero el punto es que, por defecto, Swift intenta detectar errores en tiempo de compilación. Si sabe o cree que sabe que esta variable no puede contener nulo, puede eliminar esa verificación utilizando el signo de exclamación.
lassej

16

Aquí hay unos ejemplos:

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

Donde wordes un valor opcional. significa que puede o no contener un valor.

word = name 

Aquí nametiene un valor para que podamos asignarlo

var cow:String = nil
var dog:String!

Donde dogse desenvuelve con fuerza significa que debe contener un valor

dog = cow

La aplicación se bloqueará porque estamos asignados nila desenvuelto


1
var c:Int = nilobtendrá: "Cero no puede inicializar el tipo especificado 'int'"
Asususer

15

En este caso...

var John: Persona!

significa que, inicialmente, John tendrá un valor nulo, se establecerá y una vez que se establezca, nunca volverá a estar dirigido por nada. Por lo tanto, por conveniencia, puedo usar la sintaxis más fácil para acceder a una variable opcional porque esta es una "opción implícitamente desenvuelta"


1
Gracias. También encontré el siguiente enlace que explica esto. Este tipo de tipo se denomina "opción implícitamente desenvuelta". stackoverflow.com/questions/24122601/…
Kaydell

5

Si ha venido de un lenguaje de familia C, estará pensando "puntero al objeto de tipo X, que podría ser la dirección de memoria 0 (NULL)", y si viene de un lenguaje de tipo dinámico, estará pensando "Objeto que probablemente sea de tipo X pero podría ser de tipo indefinido". Ninguno de estos es realmente correcto, aunque de manera indirecta, el primero está cerca.

La forma en que debería pensar es como si fuera un objeto como:

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

Cuando está probando su valor opcional con foo == nilrealmente está regresando foo.isNil, y cuando dice foo!que está regresando foo.realObjectcon una afirmación de que foo.isNil == false. Es importante tener en cuenta esto porque si en foorealidad es nulo cuando lo hacesfoo! , es un error de tiempo de ejecución, por lo que generalmente querría usar un let condicional en lugar de estar muy seguro de que el valor no será nulo. Este tipo de truco significa que el lenguaje puede ser fuertemente tipado sin obligarlo a probar si los valores son nulos en todas partes.

En la práctica, realmente no se comporta así porque el compilador realiza el trabajo. En un nivel alto hay un tipo Foo?que es independiente de Foo, y que evita que los funcs que aceptan el tipo Fooreciban un valor nulo, pero en un nivel bajo un valor opcional no es un objeto verdadero porque no tiene propiedades ni métodos; es probable que, de hecho, sea un puntero que puede ser NULL (0) con la prueba adecuada cuando se desenrolla a la fuerza.

Hay otra situación en la que verías un signo de exclamación en un tipo, como en:

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

Esto es más o menos equivalente a aceptar un opcional con un desenvolvimiento forzado, es decir:

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

Puede usar esto para tener un método que técnicamente acepta un valor opcional pero que tendrá un error de tiempo de ejecución si es nulo. En la versión actual de Swift, esto aparentemente pasa por alto la afirmación de no es nula, por lo que en su lugar tendrá un error de bajo nivel. Generalmente no es una buena idea, pero puede ser útil al convertir código de otro idioma.



3

Si está familiarizado con C #, esto es como los tipos anulables que también se declaran con un signo de interrogación:

Person? thisPerson;

Y el signo de exclamación en este caso es equivalente a acceder a la propiedad .Value del tipo anulable de esta manera:

thisPerson.Value

2

En el objetivo C, las variables sin valor eran iguales a 'nulo' (también era posible usar valores 'nulo' igual a 0 y falso), por lo tanto, era posible usar variables en declaraciones condicionales (las variables que tienen valores son iguales a 'VERDADERO' 'y aquellos sin valores eran iguales a' FALSO ').

Swift proporciona seguridad de tipo al proporcionar 'valor opcional'. es decir, evita errores formados al asignar variables de diferentes tipos.

Entonces, en Swift, solo se pueden proporcionar booleanos en las declaraciones condicionales.

var hw = "Hello World"

Aquí, aunque 'hw' es una cadena, no se puede usar en una declaración if como en el objetivo C.

//This is an error

if hw

 {..}

Para eso necesita ser creado como,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}

2

Los ! al final de un objeto dice que el objeto es opcional y que se desenvuelve si de lo contrario puede devolver un valor nulo. Esto a menudo se usa para atrapar errores que de otro modo bloquearían el programa.


2

En resumen (!): Después de declarar una variable y de estar seguro de que la variable tiene un valor.

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

de lo contrario, tendría que hacer esto cada vez que pase el valor ...

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

1

John es una persona opcional, lo que significa que puede tener un valor o ser nulo.

john.apartment = number73

se usa si juan no es un opcional. Como John nunca es nulo, podemos estar seguros de que no llamará a un apartamento con un valor nulo. Mientras

john!.apartment = number73

promete al compilador que John no es nulo, luego desenvuelve lo opcional para obtener el valor de John y accede a la propiedad del apartamento de John. Use esto si sabe que John no es nulo. Si llama a esto en un cero opcional, obtendrá un error de tiempo de ejecución.

La documentación incluye un buen ejemplo para usar esto donde convertNumber es opcional.

if convertedNumber {
    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}

¿Estás diciendo que si John es nulo, y yo voy john.apartment = number73, eso NO dará como resultado un error a menos que ponga un '!' despues de john?
Troy

Si juan es opcional, debe usar el signo de exclamación para acceder a sus propiedades porque el compilador debe saber que no es nulo. Si no es opcional, no puede usar el signo de exclamación.
Connor

1
Si debo usar un signo de exclamación para TODOS los vars opcionales, ¿por qué Apple incluso se molestó con él, en lugar de hacerlo, por lo que la falta de un signo de exclamación significa lo mismo? Parece una hinchazón innecesaria ... ¿O hay un caso en el que tiene sentido NO usar un signo de exclamación con una var opcional?
Troy

usa el signo de exclamación cuando necesita que el opcional no sea nulo. Como en el caso de acceder a las propiedades de juan. podrías hacer algo como var jack: ¿Persona? = juan donde jack es también un jack opcional o var: Person = john! donde jack es una persona y no es nulo
Connor

Correcto, pero, en el ejemplo original, ¿el hecho de que no esté haciendo referencia a lo johnopcional le dice al compilador que necesito que no sea nulo? ... Y en su var jack: Person = john!ejemplo, ¿no es la falta de un? ¿Después de que la persona le dice al compilador que necesita johnser no nulo? En general, lo que !parece parece un poco redundante ... Todavía siento que me falta algo en la parte del "por qué" de !...
Troy

1

En pocas palabras, los signos de exclamación significan que se está desenvolviendo un opcional. Un opcional es una variable que puede tener un valor o no, por lo que puede verificar si la variable está vacía, utilizando una instrucción if let como se muestra aquí , y luego forzar el desenvolvimiento. Sin embargo, si fuerza a desenvolver un opcional que está vacío, su programa se bloqueará, ¡así que tenga cuidado! Las opciones se declaran poniendo un signo de interrogación al final de una asignación explícita a una variable, por ejemplo, podría escribir:

var optionalExample: String?

Esta variable no tiene valor. Si lo desenvolviera, el programa se bloquearía y Xcode le diría que intentó desenvolver un opcional con un valor nulo.

Espero que haya ayudado.


1

En palabras simples

USANDO El signo de exclamación indica que la variable debe constar de un valor nulo (nunca será nulo)


1

Toda la historia comienza con una característica de swift llamada vars opcionales. Estos son los vars que pueden tener un valor o no tener un valor. En general, swift no nos permite usar una variable que no está inicializada, ya que esto puede provocar bloqueos o razones inesperadas y también un servidor de marcador de posición para puertas traseras. Por lo tanto, para declarar una variable cuyo valor no se determina inicialmente, usamos un '?'. Cuando se declara dicha variable, para usarla como parte de alguna expresión hay que desenvolverla antes de usarla, desenvolver es una operación a través de la cual se descubre el valor de una variable que se aplica a los objetos. Sin desenvolver si intentas usarlos, tendrás un error de tiempo de compilación. Para desenvolver una variable que es una var opcional, el signo de exclamación "!" es usado

Ahora hay momentos en que sabe que a tales variables opcionales se les asignarán valores por sistema, por ejemplo, o por su propio programa, pero en algún momento posterior, por ejemplo, salidas de interfaz de usuario, en tal situación en lugar de declarar una variable opcional usando un signo de interrogación "?" usamos "!".

Así, el sistema sabe que esta variable que se declara con "!" es opcional en este momento y no tiene valor, pero recibirá un valor más adelante en su vida útil.

Por lo tanto, el signo de exclamación tiene dos usos diferentes: 1. Para declarar una variable que será opcional y recibirá un valor definitivamente más tarde 2. Para desenvolver una variable opcional antes de usarla en una expresión.

Las descripciones anteriores evitan demasiadas cosas técnicas, espero.


1

Si lo usa como opcional, desenvuelve el opcional y ve si hay algo allí. Si lo usa en una declaración if-else, es un código para NOT. Por ejemplo,

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

1

Una variable opcional puede contener un valor o no

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

caso 2: var myVar:String? = nil

ahora si le preguntas a myVar !, le estás diciendo al compilador que devuelva un valor en el caso 1, devolverá "Something"

en el caso 2 se bloqueará.

Sentido ! mark forzará al compilador a devolver un valor, incluso si no está allí. Es por eso que el nombre Force Unwrapping .


@ Moritz. No sé, ¿es así? ¿No puedo responder si una pregunta ya está respondida? ¿Estoy causando algún problema o hay algo mal en mi respuesta? no entiendo ¿Por qué lo rechazas por contestarlo correctamente? Traté de responder basándome en mi comprensión del concepto. Creo que algunas personas lo encontrarán útil para una explicación clara y fácil.
Ashish Pisey

@ Moritz Ahora esto es constructivo. Deberías haberme dicho esta corrección en primer lugar, si esta fuera la razón. Gracias por la respuesta. Lo he corregido.
Ashish Pisey

0
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

1
No escriba respuestas que no agreguen nada que no haya sido cubierto por respuestas anteriores.
Dalija Prasnikar

-1

PREGÚNTESE

  • ¿El tipo person?tiene un apartmentmiembro / propiedad? O
  • ¿El tipo persontiene un apartmentmiembro / propiedad?

Si no puede responder esta pregunta, continúe leyendo:

Para comprenderlo, es posible que necesite un nivel súper básico de comprensión de los genéricos . Ver aquí . Muchas cosas en Swift se escriben usando genéricos. Opcionales incluidos

El siguiente código se ha puesto a disposición en este video de Stanford . Le recomiendo que mire los primeros 5 minutos

Un opcional es una enumeración con solo 2 casos

enum Optional<T>{
    case None
    case Some(T)
}

let x: String? = nil //actually means:

let x = Optional<String>.None

let x :String? = "hello" //actually means:

let x = Optional<String>.Some("hello")

var y = x! // actually means:

switch x {
case .Some(let value): y = value
case .None: // Raise an exception
}

Encuadernación opcional:

let x:String? = something
if let y = x {
    // do something with y
}
//Actually means:

switch x{
case .Some(let y): print)(y) // or whatever else you like using 
case .None: break
}

cuando dices var john: Person?que realmente quieres decir eso:

enum Optional<Person>{
case .None
case .Some(Person)
}

¿La enumeración anterior tiene alguna propiedad nombrada apartment? ¿Lo ves en alguna parte? Es que no hay en absoluto! Sin embargo, si lo desenvuelve, es decir, person!puede ... lo que hace debajo del capó es:Optional<Person>.Some(Person(name: "John Appleseed"))


Si hubiera definido en var john: Personlugar de: var john: Person?entonces ya no habría necesitado tener el !usado, porque Personsí tiene un miembro deapartment


Como una discusión futura sobre por qué !a veces no se recomienda usar para desenvolver, vea estas preguntas y respuestas


2
El uso de las diapositivas anteriores es posiblemente una infracción de derechos de autor: "... la Universidad de Stanford conserva los derechos de autor de todo el contenido de nuestra colección iTunes U". , de http://itunes.stanford.edu . Probablemente sea mejor responder, en sus propias palabras, el contenido que aprendió del curso que percibe para responder a esta pregunta (y en lugar de usar las diapositivas, más bien cite partes relevantes de ellas en forma de código, con referencias, naturalmente).
dfri

2
Su argumento es argumento ad populum . De todos modos, no creo que Stanford venga aquí y haga cumplir los derechos de la DMCA , pero siempre es mejor si sus respuestas están en sus propias palabras basadas en fuentes oficiales / válidas , y no en la forma de copiar esas fuentes directamente como se indicó anteriormente; especialmente cuando hablamos de diapositivas con derechos de autor: de nuevo, es mejor citar el contenido de las diapositivas en bloques de código (¡las imágenes de código son generalmente un no-no aquí en SO!).
dfri

1
La meta publicación a la que he vinculado solo describe el enfoque de SO: esto: una publicación como esta, naturalmente, no se eliminará si algún usuario aleatorio lo denuncia como una infracción de derechos de autor: solo si, por ejemplo, un representante de Stanford. iban a venir aquí y como la publicación que se eliminaría tendría que hacerla cumplir. Por lo tanto, escribí " No creo que Stanford venga aquí y haga cumplir los derechos de la DMCA, ..." . Mi punto anterior es que creo que esto es posiblemente una infracción de derechos de autor (que creo que es incorrecto), pero, naturalmente, nadie hará cumplir esto. ...
dfri

1
Pero aparte de esto, se desaconseja publicar preguntas o respuestas que contengan imágenes de código por varias razones. Para concluir: he intentado señalar con estos comentarios que creo que esta respuesta, en su forma actual, no es tan buena como podría ser, debido a dos razones principales (diapositivas con derechos de autor, imagen de código). Naturalmente, nadie, incluyéndome a mí, hará nada al respecto, simplemente lo apunto para referencia futura (o posiblemente lo aliente a editar esta publicación con una cita por bloques de código). De acuerdo, iTunes U! :)
dfri

2
@dfri eliminó imágenes
Honey
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.