What does an exclamation mark mean in the Swift la

2018-12-31 06:29发布

The Swift Programming Language guide has the following example:

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)

Then when assigning the apartment to the person, they use an exclamation point to "unwrap the instance":

john!.apartment = number73

What does it mean to "unwrap the instance"? Why is it necessary? How is it different from just doing the following:

john.apartment = number73

I'm very new to the Swift language. Just trying to get the basics down.


UPDATE:
The big piece of the puzzle that I was missing (not directly stated in the answers - at least not at the time of writing this) is that when you do the following:

var john: Person?

that does NOT mean that "john is of type Person and it might be nil", as I originally thought. I was simply misunderstanding that Person and Person? are completely separate types. Once I grasped that, all of the other ?, ! madness, and the great answers below, made a lot more sense.

22条回答
浪荡孟婆
2楼-- · 2018-12-31 06:34

TL;DR

What does an exclamation mark mean in the Swift language?

The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value:

Example

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

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

查看更多
刘海飞了
3楼-- · 2018-12-31 06:36
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
查看更多
美炸的是我
4楼-- · 2018-12-31 06:38

john is an optional var. So can be contains a nil value. To ensure that the value isn't nil use a ! at the end of the var name.

From documentation

“Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.”

Another way to check non nil value is

    if let j = json {
        // do something with j
    }
查看更多
深知你不懂我心
5楼-- · 2018-12-31 06:39

If you've come from a C-family language, you will be thinking "pointer to object of type X which might be the memory address 0 (NULL)", and if you're coming from a dynamically typed language you'll be thinking "Object which is probably of type X but might be of type undefined". Neither of these is actually correct, although in a roundabout way the first one is close.

The way you should be thinking of it is as if it's an object like:

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

When you're testing your optional value with foo == nil it's really returning foo.isNil, and when you say foo! it's returning foo.realObject with an assertion that foo.isNil == false. It's important to note this because if foo actually is nil when you do foo!, that's a runtime error, so typically you'd want to use a conditional let instead unless you are very sure that the value will not be nil. This kind of trickery means that the language can be strongly typed without forcing you to test if values are nil everywhere.

In practice, it doesn't truly behave like that because the work is done by the compiler. At a high level there is a type Foo? which is separate to Foo, and that prevents funcs which accept type Foo from receiving a nil value, but at a low level an optional value isn't a true object because it has no properties or methods; it's likely that in fact it is a pointer which may by NULL(0) with the appropriate test when force-unwrapping.

There other situation in which you'd see an exclamation mark is on a type, as in:

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

This is roughly equivalent to accepting an optional with a forced unwrap, i.e.:

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

You can use this to have a method which technically accepts an optional value but will have a runtime error if it is nil. In the current version of Swift this apparently bypasses the is-not-nil assertion so you'll have a low-level error instead. Generally not a good idea, but it can be useful when converting code from another language.

查看更多
呛了眼睛熬了心
6楼-- · 2018-12-31 06:39

If you're familiar with C#, this is like Nullable types which are also declared using a question mark:

Person? thisPerson;

And the exclamation mark in this case is equivalent to accessing the .Value property of the nullable type like this:

thisPerson.Value
查看更多
听够珍惜
7楼-- · 2018-12-31 06:42

In this case...

var John: Person!

it means, that initially John will have nil value, it will be set and once set will never be nil-led again. Therefore for convenience I can use the easier syntax for accessing an optional var because this is an "Implicitly unwrapped optional"

查看更多
登录 后发表回答