O que significa um ponto de exclamação no idioma Swift?


518

O guia Swift Programming Language tem o seguinte exemplo:

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)

Em seguida, ao atribuir o apartamento à pessoa, eles usam um ponto de exclamação para "desembrulhar a instância":

john!.apartment = number73

O que significa "desembrulhar a instância"? Por que isso é necessário? Como é diferente de apenas fazer o seguinte:

john.apartment = number73

Eu sou muito novo na linguagem Swift. Apenas tentando entender o básico.


ATUALIZAÇÃO:
A grande parte do quebra-cabeça que eu estava perdendo (não declarada diretamente nas respostas - pelo menos não no momento em que escrevi isso) é que, quando você faz o seguinte:

var john: Person?

isso NÃO significa que " johné do tipo Persone pode ser nulo", como eu pensava originalmente. Eu estava simplesmente entendendo isso errado Persone Person?são tipos completamente separados. Uma vez compreendi isso, todas as outras ?, !loucura e as grandes respostas abaixo, fizeram muito mais sentido.

Respostas:


530

O que significa "desembrulhar a instância"? Por que isso é necessário?

Tanto quanto eu posso trabalhar (isso também é muito novo para mim) ...

O termo "embrulhado" implica que devemos pensar em uma variável opcional como um presente, embrulhado em papel brilhante, que pode (infelizmente!) Estar vazio .

Quando "empacotado", o valor de uma variável Opcional é uma enumeração com dois valores possíveis (um pouco como um Booleano). Esta enumeração descreve se a variável possui um valor ( Some(T)) ou não ( None).

Se houver um valor, isso pode ser obtido "desembrulhando" a variável (obtendo a Tpartir de Some(T)).

Qual é a john!.apartment = number73diferença john.apartment = number73? (Parafraseado)

Se você escrever o nome de uma variável Opcional (por exemplo john, texto , sem a !), isso se refere à enumeração "empacotada" (Alguma / Nenhuma), não ao valor em si (T). Portanto, johnnão é uma instância de Persone não possui um apartmentmembro:

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

O Personvalor real pode ser desembrulhado de várias maneiras:

  • "desembrulhar forçado": john!(fornece o Personvalor, se existir, erro de tempo de execução, se for nulo)
  • "ligação opcional": if let p = john { println(p) }(executa printlnse o valor existe)
  • "encadeamento opcional": john?.learnAboutSwift()(executa este método inventado se o valor existir)

Eu acho que você escolhe uma dessas maneiras de desembrulhar, dependendo do que deve acontecer no caso nulo e da probabilidade disso. Esse design de linguagem força o caso nulo a ser tratado explicitamente, o que eu suponho melhora a segurança em relação ao Obj-C (onde é fácil esquecer o tratamento do caso nulo).

Atualização :

O ponto de exclamação também é usado na sintaxe para declarar "Opcionais Implicitamente Desembrulhados".

Nos exemplos até agora, a johnvariável foi declarada como var john:Person?e é uma Opcional. Se você deseja o valor real dessa variável, deve desembrulhá-la, usando um dos três métodos acima.

Se fosse declarada como var john:Person!alternativa, a variável seria um opcional implicitamente desembrulhado (consulte a seção com este cabeçalho no livro da Apple). Não há necessidade de desembrulhar esse tipo de variável ao acessar o valor e johnpode ser usado sem sintaxe adicional. Mas o livro da Apple diz:

Opcionais implicitamente desembrulhados não devem ser usados ​​quando houver a possibilidade de uma variável se tornar nula posteriormente. Sempre use um tipo opcional normal se precisar verificar um valor nulo durante a vida útil de uma variável.

Atualização 2 :

O artigo " Recursos rápidos e interessantes " de Mike Ash fornece alguma motivação para os tipos opcionais. Eu acho ótimo escrever com clareza.

Atualização 3 :

Outro artigo útil sobre o uso opcional implicitamente desembrulhado do ponto de exclamação: " Swift and the Last Mile ", de Chris Adamson. O artigo explica que essa é uma medida pragmática da Apple usada para declarar os tipos usados ​​por suas estruturas de Objective-C que podem conter nulo. Declarar um tipo como opcional (usando ?) ou desembrulhado implicitamente (usando !) é "uma troca entre segurança e conveniência". Nos exemplos dados no artigo, a Apple optou por declarar os tipos como implicitamente desembrulhados, tornando o código de chamada mais conveniente, mas menos seguro.

Talvez a Apple possa vasculhar suas estruturas no futuro, removendo a incerteza de parâmetros implicitamente desembrulhados ("provavelmente nunca nulos") e substituindo-os por parâmetros opcionais ("certamente poderia ser nulo em particular [espero, documentado!] Circunstâncias") ou não padrão -opcional ("nunca é nulo"), com base no comportamento exato do código Objective-C.


Não tenho certeza sobre essa explicação. Se você acabou de executar o código sem o! ainda retorna o valor real. Talvez o ! é para velocidade?
Richard Washington

ESTÁ BEM. Então, os documentos falam sobre o uso! quando tiver certeza de que pode ser desembrulhado. Mas você pode executar o código sem ele (uma quarta opção para sua lista - desempacotamento implícito) E sem verificar primeiro. Você recupera o valor ou nulo se nulo. Mas se você tiver certeza de que não é nulo, use! ...... mas ainda não consigo ver por que você faria isso?
Richard Washington

2
Oi @RichardWashington - Adicionei uma atualização à minha resposta, que espero esclarecer um pouco disso.
Ashley

A atualização 3 é exatamente o que estou procurando. Antes de lê-lo, pensei que a Apple estivesse mentindo quando eles retornaram algo como NSURLCredential! o que realmente pode ser nulo.
Golden Thumb

Obrigado pela resposta fantástica @Ashley. Depois de ler esta resposta e alguns dos códigos rápidos de exemplo da Apple, parece-me realmente que nessa troca entre segurança e produtividade, geralmente é melhor estar do lado mais seguro. Uma exceção notável que encontrei é quando a Apple usa o desembrulhamento forçado para elementos da interface do usuário, o que faz sentido porque, em primeiro lugar, os elementos da interface do usuário geralmente são opcionais ao envolver um storyboard (como não recebem um valor programaticamente) e, em segundo lugar, porque são quase nunca nulo, a menos que o controlador de exibição contido seja nulo; nesse caso, essa discussão será discutível.
Mihir 23/07

127

Aqui está o que eu acho que é a diferença:

var john: Person?

Significa que john pode ser nulo

john?.apartment = number73

O compilador interpretará essa linha como:

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

Enquanto

john!.apartment = number73

O compilador interpretará essa linha como simplesmente:

john.apartment = number73

Portanto, usando! desempacotará a instrução if e a executará mais rapidamente, mas se john for nulo, ocorrerá um erro de tempo de execução.

Então, agrupar aqui não significa que é agrupado em memória, mas significa que é agrupado em código; nesse caso, é agrupado com uma instrução if e, como a Apple presta muita atenção ao desempenho em tempo de execução, eles querem oferecer uma maneira de faça seu aplicativo funcionar com o melhor desempenho possível.

Atualizar:

Voltando a esta resposta após 4 anos, pois obtive a maior reputação no Stackoverflow :) Eu entendi um pouco o significado de desembrulhar na época. Agora, depois de quatro anos, acredito que o significado de desembrulhar aqui é expandir o código de sua forma compacta original. Também significa remover a imprecisão em torno desse objeto, pois, por definição, não temos certeza se é nulo ou não. Assim como a resposta de Ashley acima, pense nisso como um presente que não pode conter nada. Mas ainda acho que o desempacotamento é desembrulhado por código e não desempacotado com base na memória como usando enum.


9
Em meu playground john.apartment = number73 não compilar, você deve especificar john .Apartamento = number73?
Chuck Pinkert

2
@ChuckPinkert está certo, a quarta linha deve ser editada para john? .Apartment = number73, embora seja uma boa resposta!
Bruce

john.apartment = number73 fornece error: value do tipo opcional 'Person?' não desembrulhado: você quis usar '!' ou '?'?
spiderman

4
O desembrulhar não tem nada a ver com desempenho errado. A "verificação nula" ainda precisa ser feita no tempo de execução, a única diferença é que um erro de tempo de execução será gerado caso nenhum valor esteja presente no Opcional.
madidier

67

TL; DR

O que significa um ponto de exclamação no idioma Swift?

O ponto de exclamação diz efetivamente: “Eu sei que esse opcional definitivamente tem um valor; por favor, use-o. ” Isso é conhecido como desempacotamento forçado do valor do opcional:

Exemplo

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

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


11
Sua resposta é ótima, porque eu entendo o que está acontecendo agora. O que não entendo é por que existem opcionais implicitamente desembrulhados. Por que criar algo definido como uma String opcional implicitamente desembrulhada, em vez de um tipo String regular? Seu uso depois é o mesmo. o que estou perdendo?
Pachun

Isso não parece mais ser verdade. Em um Swift 5 repl, se eu fizer let f: String! = "hello"e então print(f), a saída é em Optional("hello")vez de apenas "hello".
numbermaniac

37

Se john fosse um var opcional (declarado assim)

var john: Person?

seria possível que john não tivesse valor (na linguagem ObjC, valor nulo)

O ponto de exclamação basicamente diz ao compilador "Eu sei que isso tem um valor, você não precisa testá-lo". Se você não quiser usá-lo, poderá testá-lo condicionalmente:

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

O interior disso avaliará apenas se john tem um valor.


4
Obrigado pela resposta, agora entendo o que o ponto de exclamação diz, ainda estou tentando entender o porquê ... Você disse que diz ao compilador "Eu sei que isso tem um valor, você não precisa testar isto". O que me compra quando o compilador não faz o teste? Sem o ponto de exclamação, o compilador irá gerar um erro (ainda não tenho um ambiente, onde posso testar o Swift)? É o ! 100% necessário para todos os vars opcionais? Se sim, por que a Apple se preocupou com isso, em vez de apenas fazer com que a falta de! significa "Eu sei que isso tem um valor, você não precisa testá-lo"?
Troy

"o compilador irá lançar um erro" - não, ainda funciona bem retornando o valor conforme o esperado. Eu não entendo isso. É o ! só pela velocidade quando tiver certeza, talvez?
Richard Washington

De fato, mais adiante, os documentos falam sobre opcionais implicitamente desembrulhados usando o exemplo abaixo: “let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.” Mas funciona bem sem! Algo parece estranho aqui.
Richard Washington

3
@RichardWashington Você está confuso por um bom motivo! Os exemplos nos documentos estão deixando algumas coisas de fora e são enganosas, porque tudo o que fazem é usar println. Aparentemente, há pelo menos alguns casos em que não é necessário desembrulhar os opcionais. Uma é ao usar println. Outra é quando se usa interpolação de string. Então, talvez a interpolação println e string estejam desembrulhando debaixo das cobertas? Talvez alguém tenha mais informações sobre isso. Observar as definições de cabeçalho do Xcode6 Beta não me revelou nada sobre essa mágica.
mbeaty

Sim, eu entendo isso John?e Johnsão dois tipos diferentes. Um é do tipo Pessoa Opcional e o outro Tipo Pessoa. O Person opcional precisa ser desembrulhado antes que você possa tirá-lo. Mas, como você diz, isso parece acontecer pelo menos nessas circunstâncias sem ter que realmente fazer nada. Isso parece fazer o! redundante. A menos que o! SEMPRE é opcional, mas é recomendável sugerir erros de compilação. Como atribuir vars / lets a um tipo específico, pode ser explícito, let John: Person = ...mas também pode ser inferido let John = ....
Richard Washington

27

Alguma perspectiva geral para adicionar a outras respostas úteis, mas mais centradas em detalhes:

No Swift, o ponto de exclamação aparece em vários contextos:

  • Desembrulhamento forçado: let name = nameLabel!.text
  • Opcionais implicitamente desembrulhados: var logo: UIImageView!
  • Fundição forçada: logo.image = thing as! UIImage
  • Exceções não tratadas: try! NSJSONSerialization.JSONObjectWithData(data, [])

Cada uma delas é uma construção de linguagem diferente, com um significado diferente, mas todas elas têm três coisas importantes em comum:

1. Os pontos de exclamação contornam as verificações de segurança em tempo de compilação do Swift.

Quando você usa o !Swift, está basicamente dizendo: “Ei, compilador, eu sei que você acha que um erro pode acontecer aqui, mas eu sei com total certeza que isso nunca acontecerá".

Nem todo código válido se encaixa na caixa do sistema de tipos de tempo de compilação do Swift - ou na verificação estática de qualquer tipo de idioma, nesse caso. Há situações em que você pode provar logicamente que nunca ocorrerá um erro, mas não o poderá provar ao compilador . É por isso que os designers da Swift adicionaram esses recursos em primeiro lugar.

No entanto, sempre que você usa !, está descartando um caminho de recuperação para um erro, o que significa que…

2. Pontos de exclamação são possíveis falhas.

Um ponto de exclamação também diz: "Hey Swift, tenho tanta certeza de que esse erro nunca pode acontecer que é melhor você travar meu aplicativo inteiro do que codificar um caminho de recuperação para ele".

Essa é uma afirmação perigosa. ele pode ser o correto: no código de missão crítica, onde você tem pensado muito sobre invariantes do seu código, pode ser que a saída falsa é pior do que um acidente.

No entanto, quando vejo !na natureza, raramente é usado com tanta atenção. Em vez disso, muitas vezes significa: "esse valor era opcional e eu realmente não pensei muito sobre por que poderia ser nulo ou como lidar adequadamente com essa situação, mas a adição !fez com que fosse compilada ... para que meu código esteja correto, certo?"

Cuidado com a arrogância do ponto de exclamação. Em vez de…

3. Os pontos de exclamação são melhor usados ​​com moderação.

Cada uma dessas !construções possui uma ?contraparte que o força a lidar com o caso de erro / zero:

  • Desempacotamento condicional: if let name = nameLabel?.text { ... }
  • Opcionais: var logo: UIImageView?
  • Elenco condicional: logo.image = thing as? UIImage
  • Exceções de zero em falha: try? NSJSONSerialization.JSONObjectWithData(data, [])

Se você é tentado a usar !, é sempre bom considerar cuidadosamente por que você não está usando ?. Falhando no seu programa é realmente a melhor opção se a !operação falhar? Por que esse valor é opcional / disponível?

Existe um caminho de recuperação razoável que seu código poderia seguir no caso de nulo / erro? Se sim, codifique-o.

Se não puder ser nulo, se o erro nunca ocorrer, existe uma maneira razoável de refazer sua lógica para que o compilador saiba disso? Se sim, faça; seu código será menos propenso a erros.

Há momentos em que não há uma maneira razoável de lidar com um erro, e simplesmente ignorá-lo - e, assim, prosseguir com dados errados - seria pior do que travar. Esses são os momentos para usar a força de desembrulhar.

Eu procuro periodicamente toda a minha base de código !e audito cada uso dela. Muito poucos usos resistem ao escrutínio. (Até o momento em que este artigo foi escrito, toda a estrutura do Siesta possui exatamente duas instâncias .)

Isso não quer dizer que você nunca deve usar !seu código - apenas que você deve usá-lo com atenção e nunca torná-lo a opção padrão.


func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) } Dado 3. existe uma maneira melhor de escrever?
Jenson-button-event

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

Os pontos de exclamação não contornam nenhuma verificação de segurança. Você obtém uma falha garantida se o opcional for nulo. O opcional é sempre verificado. É apenas uma maneira muito brutal de fazer uma verificação de segurança.
precisa saber é o seguinte

@ gnasher729 Como a resposta indica, ela contorna as verificações de segurança em tempo de compilação, favorecendo uma falha de tempo de execução seguro .
Paul Cantrell

24

johné um opcional var. Então pode ser contém um nilvalor. Para garantir que o valor não seja nulo, use a !no final do varnome.

Da documentação

“Depois de ter certeza de que o opcional contém um valor, você pode acessar o valor subjacente adicionando um ponto de exclamação (!) Ao final do nome do opcional. O ponto de exclamação diz efetivamente: “Eu sei que esse opcional definitivamente tem um valor; por favor, use-o. ”

Outra maneira de verificar o valor não nulo é

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

1
Sim, eu já tinha visto isso na documentação, mas ainda parece desnecessário ... pois, para mim, john.apartment = number73também diz "Eu sei que esse opcional definitivamente tem um valor; por favor, use-o." ...
Troy

6
Sim, mas o ponto é que, por padrão, o Swift tenta capturar erros em tempo de compilação. Se você souber ou achar que essa variável não pode conter nada, remova essa verificação usando o ponto de exclamação.
lassej

16

aqui estão alguns exemplos:

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

Onde wordé um valor opcional. significa que pode ou não conter um valor.

word = name 

Aqui nametem um valor para que possamos atribuí-lo

var cow:String = nil
var dog:String!

Onde dogfor desembrulhado com força significa que deve conter um valor

dog = cow

O aplicativo falhará porque somos atribuídos nila desembrulhados


1
var c:Int = nilirá receber: "Nil não pode inicializar o tipo especificado 'int'"
Asususer 01/08/17

15

Nesse caso...

var John: Pessoa!

significa que, inicialmente, John terá valor nulo, será definido e, uma vez definido, nunca será nulo novamente. Portanto, por conveniência, posso usar a sintaxe mais fácil para acessar uma var opcional, porque esta é uma "Opcional implicitamente desembrulhada"


1
Obrigado. Eu também encontrei o seguinte link que explica isso. Esse tipo de tipo é chamado de "opção implicitamente desembrulhada". stackoverflow.com/questions/24122601/…
Kaydell

5

Se você veio de uma linguagem da família C, estará pensando em "ponteiro para objeto do tipo X, que pode ser o endereço de memória 0 (NULL)", e se você vier de uma linguagem de tipo dinâmico, será pensando "Objeto que provavelmente é do tipo X, mas pode ser do tipo indefinido". Nenhuma delas está realmente correta, embora de maneira indireta a primeira esteja próxima.

A maneira como você deve pensar nisso é como se fosse um objeto como:

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

Quando você está testando seu valor opcional, foo == nilele realmente está retornando foo.isNile quando você diz foo!que está retornando foo.realObjectcom uma afirmação de que foo.isNil == false. É importante observar isso, porque se foorealmente for nulo quando você fazfoo! isso, é um erro de tempo de execução; portanto, normalmente você deseja usar uma permissão condicional, a menos que tenha certeza de que o valor não será nulo. Esse tipo de truque significa que o idioma pode ser fortemente digitado sem forçar você a testar se os valores são nulos em todos os lugares.

Na prática, ele realmente não se comporta assim porque o trabalho é feito pelo compilador. Em um nível alto, há um tipo Foo?que é separado Fooe impede que as funções que aceitam o tipo Foorecebam um valor nulo, mas, em um nível baixo, um valor opcional não é um objeto verdadeiro porque não possui propriedades ou métodos; é provável que, de fato, seja um ponteiro que pode, por NULL (0), com o teste apropriado ao desembrulhar à força.

Há outra situação em que você vê um ponto de exclamação em um tipo, como em:

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

Isso é aproximadamente equivalente a aceitar um opcional com um desembrulhamento forçado, ou seja:

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

Você pode usar isso para ter um método que aceite tecnicamente um valor opcional, mas que terá um erro de tempo de execução se for nulo. Na versão atual do Swift, isso aparentemente ignora a asserção não é nada, então você terá um erro de baixo nível. Geralmente não é uma boa ideia, mas pode ser útil ao converter código de outro idioma.



3

Se você conhece C #, são tipos Nullable que também são declarados usando um ponto de interrogação:

Person? thisPerson;

E o ponto de exclamação, neste caso, é equivalente a acessar a propriedade .Value do tipo anulável como este:

thisPerson.Value

2

No objetivo C, variáveis ​​sem valor eram iguais a 'nil' (também era possível usar valores 'nil' iguais a 0 e false); portanto, era possível usar variáveis ​​em declarações condicionais (variáveis ​​com valores iguais a 'TRUE 'e aqueles sem valores foram iguais a' FALSE ').

Swift fornece segurança de tipo, fornecendo 'valor opcional'. ou seja, evita erros formados de atribuir variáveis ​​de tipos diferentes.

Portanto, no Swift, apenas booleanos podem ser fornecidos em instruções condicionais.

var hw = "Hello World"

Aqui, mesmo que 'hw' seja uma string, ela não pode ser usada em uma instrução if como no objetivo C.

//This is an error

if hw

 {..}

Para isso, ele precisa ser criado como,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}

2

O ! no final de um objeto, o objeto é opcional e é desembrulhado, se puder retornar um valor nulo. Isso geralmente é usado para capturar erros que, de outra forma, travariam o programa.


2

Resumindo (!): Depois de declarar uma variável e ter certeza de que a variável está mantendo um valor.

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

caso contrário, você teria que fazer isso sempre que passar o valor ...

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

1

João é uma Pessoa opcional, o que significa que pode conter um valor ou ser nulo.

john.apartment = number73

é usado se john não for opcional. Como john nunca é nulo, podemos ter certeza de que não chamará apartamento com um valor nulo. Enquanto

john!.apartment = number73

promete ao compilador que john não é nulo, desembrulha o opcional para obter o valor de john e acessa a propriedade do apartamento de john. Use isso se você souber que john não é nulo. Se você chamar isso de opcional nulo, você receberá um erro de tempo de execução.

A documentação inclui um bom exemplo para usá-lo, em que convertNumber é opcional.

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

Você está dizendo que se john for nulo, e eu for john.apartment = number73, isso não resultará em erro, a menos que eu coloque um '!' depois de john?
Troy

Se john é um opcional, você deve usar o ponto de exclamação para acessar suas propriedades, porque o compilador deve saber que não é nulo. Se não for opcional, não será possível usar o ponto de exclamação.
Connor

1
Se devo usar um ponto de exclamação para TODOS os vars opcionais, por que a Apple se incomodou com ele, em vez de fazê-lo, de modo que a falta de um ponto de exclamação signifique a mesma coisa? Parece inchaço desnecessário ... Ou existe um caso em que faz sentido NÃO usar um ponto de exclamação com um var opcional?
Troy

você usa o ponto de exclamação quando precisa que o opcional não seja nulo. Como no caso de acessar propriedades de john. você poderia fazer algo como var jack: Pessoa? = john, onde jack também é um jack opcional ou var: Person = john! onde Jack é uma pessoa e não é nulo
Connor

Certo, mas, no exemplo original, o fato de eu não fazer referência ao johnopcional diz ao compilador que eu preciso que ele não seja nulo? ... E no seu var jack: Person = john!exemplo, a falta de um? depois de Person dizer ao compilador que você precisa johnser não nulo? No geral, a !apenas parece parece meio redundante ... Ele ainda se sente como eu estou faltando alguma coisa sobre o "porquê" parte do !...
Troy

1

Simplificando, pontos de exclamação significam que um opcional está sendo desembrulhado. Uma opcional é uma variável que pode ter um valor ou não - para que você possa verificar se a variável está vazia, usando uma instrução if let, como mostrado aqui , e depois forçar a desembrulhar. Se você forçar a desembrulhar um opcional vazio, seu programa falhará, portanto, tenha cuidado! Os opcionais são declarados colocando um ponto de interrogação no final de uma atribuição explícita a uma variável, por exemplo, eu poderia escrever:

var optionalExample: String?

Esta variável não tem valor. Se eu o desembrulhasse, o programa falharia e o Xcode lhe diria que você tentou desembrulhar um opcional com um valor nulo.

Espero que tenha ajudado.


1

EM PALAVRAS SIMPLES

USANDO O ponto de exclamação indica que a variável deve consistir em um valor nulo (nunca será nulo)


1

Toda a história começa com um recurso rápido chamado vars opcionais. Estes são os vars que podem ter um valor ou podem não ter um valor. Em geral, o swift não nos permite usar uma variável que não foi inicializada, pois isso pode levar a falhas ou razões inesperadas e também servir como um espaço reservado para backdoors. Assim, para declarar uma variável cujo valor não é determinado inicialmente, usamos um '?'. Quando uma variável é declarada, para usá-la como parte de alguma expressão que é necessária para desembrulhá-la antes do uso, desembrulhar é uma operação pela qual o valor de uma variável é descoberto, isso se aplica aos objetos. Sem desembrulhar, se você tentar usá-los, terá um erro de tempo de compilação. Para desembrulhar uma variável que é uma var opcional, ponto de exclamação "!" é usado.

Agora, há momentos em que você sabe que essas variáveis ​​opcionais receberão valores pelo sistema, por exemplo, ou por seu próprio programa, mas algum tempo depois, por exemplo, pontos de interface do usuário, nessa situação, em vez de declarar uma variável opcional usando um ponto de interrogação "?" nós usamos "!".

Assim, o sistema sabe que essa variável que é declarada com "!" é opcional no momento e não tem valor, mas receberá um valor posteriormente.

Assim, o ponto de exclamação possui dois usos diferentes: 1. Declarar uma variável que será opcional e receberá valor definitivamente mais tarde 2. Desembrulhar uma variável opcional antes de usá-la em uma expressão.

As descrições acima evitam muito material técnico, espero.


1

Se você o usar como opcional, ele desembrulha o opcional e verifica se há algo lá. Se você usá-lo em uma instrução if-else is é código para NOT. Por exemplo,

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

1

Uma variável opcional pode conter um valor ou pode não ser

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

caso 2: var myVar:String? = nil

Agora, se você perguntar ao myVar !, você está dizendo ao compilador para retornar um valor no caso 1, ele retornará "Something"

no caso 2, ele travará.

Significado! A marca forçará o compilador a retornar um valor, mesmo que não esteja lá. é por isso que o nome Force Unwrapping .


@Moritz. Eu não sei, é isso? Não posso responder se uma pergunta já foi respondida? Estou causando algum problema ou há algo errado na minha resposta? Eu não entendo Por que você está votando para responder corretamente? Tentei responder com base na minha compreensão do conceito. Eu acho que algumas pessoas acharão útil uma explicação clara e fácil.
Ashish Pisey

@ Moritz Agora isso é construtivo. Você deveria ter me dito essa correção em primeiro lugar, se esse era o motivo. Obrigado pelo feedback. Eu o corrigi.
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
Por favor, não escreva respostas que não estejam adicionando nada que ainda não tenha sido coberto por respostas anteriores.
Dalija Prasnikar

-1

PERGUNTE-SE

  • O tipo person?tem umapartment membro / propriedade? OU
  • O tipo persontem um apartmentmembro / propriedade?

Se você não conseguir responder a essa pergunta, continue lendo:

Para entender, você pode precisar de um nível super básico de compreensão de genéricos . Veja aqui . Muitas coisas no Swift são escritas usando Genéricos. Opcionais incluídos

O código abaixo foi disponibilizado neste vídeo de Stanford . Recomendo que você assista os primeiros 5 minutos

Um opcional é um enum com apenas 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
}

Ligação 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
}

quando você diz que var john: Person?realmente quer dizer isso:

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

A enumeração acima tem alguma propriedade chamada apartment? Você vê em algum lugar? É não existe em tudo! No entanto, se você desembrulhá-lo, ou seja person!, você pode ... o que ele faz sob o capô é:Optional<Person>.Some(Person(name: "John Appleseed"))


Se você tivesse definido em var john: Personvez de: var john: Person?então não precisaria mais ter o !usado, porque Personele próprio tem um membro deapartment


Como uma discussão futura sobre por que o uso !do desembrulhar às vezes não é recomendado, consulte esta seção de perguntas e respostas


2
O uso dos slides reais acima é possivelmente uma violação de direitos autorais: "... A Universidade de Stanford mantém os direitos autorais de todo o conteúdo de nossa coleção do iTunes U". , de http://itunes.stanford.edu . Provavelmente é melhor responder, com suas próprias palavras, o conteúdo que aprendeu no curso que você considera responder a essa pergunta (e, em vez de usar os slides, cite partes relevantes delas em forma de código, com referências, naturalmente).
DFRI

2
Seu argumento é argumentum ad populum . De qualquer forma, não acredito que Stanford venha aqui e faça valer os direitos de DMCA , mas sempre será melhor se suas respostas estiverem em suas próprias palavras, com base em fontes oficiais / válidas , e não na forma de copiar essas fontes diretamente como acima; especialmente quando falamos de slides protegidos por direitos autorais: novamente, é melhor citar o conteúdo dos slides em blocos de código (as imagens de código geralmente são um não-não aqui no SO!).
DFRI

1
O meta post ao qual eu vinculei descreve apenas a abordagem SO: para isso: um post como esse não será removido naturalmente se algum usuário aleatório o relatar como violação de direitos autorais: somente se, por exemplo, um representante de Stanford. viriam aqui e, como a postagem a ser removida, precisaria impor isso. Por isso, escrevi " Não acredito que Stanford venha aqui e faça valer os direitos da DMCA, ..." . Meu argumento acima é que acredito que isso seja possivelmente uma violação de direitos autorais (que acredito estar errada), mas, naturalmente, ninguém nunca aplicará isso. ...
DFRI

1
Mas, deixando de lado, postar perguntas ou respostas que contenham imagens de código é desencorajado por vários motivos. Para encerrar: tentei apontar com esses comentários que acredito que essa resposta, em sua forma atual, não é tão boa quanto poderia ser, devido a duas razões principais (slides com direitos autorais, imagem de código). Naturalmente, ninguém, inclusive eu, fará algo a respeito, estou apenas apontando para referência futura (ou possivelmente incentivando você a editar este post com citação por blocos de código). Concordo, iTunes U! :)
DFRI

2
@dfri removeu imagens
Honey
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.