web-dev-qa-db-ja.com

Swift言語で感嘆符はどういう意味ですか?

Swiftプログラミング言語ガイド には、次の例があります。

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)

それからアパートを人に割り当てるとき、彼らは「インスタンスをアンラップする」ために感嘆符を使います:

john!.apartment = number73

「インスタンスのラップを解除する」とはどういう意味ですか?なぜそれが必要なのですか?次のようなこととはどう違うのですか。

john.apartment = number73

私はSwift言語にとても慣れていません。基本をやろうとしているだけです。


UPDATE:
私が見逃していた(少なくとも答えを書いている時点ではありませんが)このパズルの大きな部分は、あなたが次のことをしたときです。

var john: Person?

私が最初に思ったように、それは「johnPerson型であり、それがnilであるかもしれない」という意味ではありません。私は単にPersonPerson?は完全に別の型であると誤解しました。私がそれを把握したら、他のすべての?!の狂気、そして以下の素晴らしい答えは、もっとずっと理にかなったものになりました。

505
Troy

「インスタンスのラップを解除する」とはどういう意味ですか?なぜそれが必要なのですか?

私ができる限り(これも私にとっては非常に新しいことです)...

"wrapped"という用語は、 Optional変数を光沢のある紙に包まれたプレゼントとして考えることを意味します。(残念ながら)空になることもあります

「ラップ」されると、Optional変数の値は2つの可能な値を持つenumです(ブール値に少し似ています)。この列挙型は、変数が値を保持しているか(Some(T))、保持していないか(None)を示します。

値がある場合は、変数の「ラップを解除する」(Some(T)からTを取得する)ことによって取得できます。

john!.apartment = number73john.apartment = number73とどう違うのですか? (言い換えれば)

Optional変数の名前(例えば!のないテキストjohn)を書く場合、これは値それ自体(T)ではなく、「ラップされた」enum(Some/None)を参照します。したがって、johnPersonのインスタンスではなく、apartmentメンバーを持ちません。

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

実際のPerson値は様々な方法でアンラップすることができます。

  • "強制的なアンラッピング":john!(存在する場合はPerson値を、それがnilの場合はランタイムエラーを返します)
  • "optional binding":if let p = john { println(p) }(値が存在する場合はprintlnを実行します)
  • "optional chaining":john?.learnAboutSwift()(値が存在する場合はこの補完メソッドを実行します)

このケースで何が起こるべきか、そしてそれがどれほどありそうかに応じて、アンラップするためにこれらの方法の1つを選択すると思います。この言語設計により、nilの場合は明示的に処理されるようになり、Obj-C(nilの場合を忘れるのは簡単です)よりも安全性が向上します。

更新

感嘆符は、「暗黙的にラップされていないオプション」を宣言するための構文でも使用されます。

これまでの例では、john変数はvar john:Person?として宣言されており、これはOptionalです。その変数の実際の値が必要な場合は、上記の3つの方法のいずれかを使用してそれをアンラップする必要があります。

代わりにvar john:Person!として宣言されている場合、変数は暗黙的にラップされていないオプションになります(Appleの本のこの見出しを持つセクションを参照してください)。値にアクセスするときにこの種の変数を展開する必要はなく、johnは追加の構文なしで使用できます。しかし、Appleの本は言う:

変数が後でnilになる可能性がある場合は、暗黙的にラップされていないオプションを使用しないでください。変数の有効期間中にnil値をチェックする必要がある場合は、常に通常のオプションの型を使用してください。

更新2

Mike Ashによる " おもしろいSwift Features "という記事は、オプション型の動機をいくつか示しています。それは素晴らしい、明確な文章だと思います。

更新3

感嘆符としての暗黙的にラップされていないオプションの使用に関するもう1つの有用な記事:Chris Adamsonによる " Swift and the Last Mile "。この記事では、これが、nilを含む可能性があるObjective-Cフレームワークで使用される型を宣言するために使用されていたAppleによる実用的な方法であることを説明しています。型をオプション(?を使用)または暗黙的にラップ解除(!を使用)として宣言することは、「安全性と利便性の間のトレードオフ」です。この記事の例では、Appleは型を暗黙のうちにラップされていないものとして宣言することを選択しました。これにより、呼び出しコードがより便利になりますが、安全性が低下します。

おそらくAppleは将来自分たちのフレームワークをくぐり抜けて、暗黙のうちにラップされていない(「おそらく無駄」な)パラメータの不確実性を取り除き、それらをオプションの(「確実に無駄になる」 Objective-Cコードの正確な動作に基づく-optional( "never never nil")宣言。

514
Ashley

これが私が違いだと思うものです:

var john: Person?

Johnという手段はゼロにすることができます

john?.apartment = number73

コンパイラはこの行を次のように解釈します。

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

しながら

john!.apartment = number73

コンパイラはこの行を単に次のように解釈します。

john.apartment = number73

だから、使って! if文をアンラップして実行速度を上げますが、johnがnilの場合、実行時エラーが発生します。

したがって、ここで折り返すとは、メモリで折り返されることを意味するのではなく、コードで折り返されることを意味します。この場合はifステートメントで折り返されます。アプリを可能な限り最高のパフォーマンスで実行します。

更新:

私がStackoverflowでそれから最高の評判を得たので、4年後にこの答えに戻ります:)私はその時に開けることの意味を少し誤解しました。 4年経った今、ここで展開することの意味は、元のコンパクトな形式からコードを拡張することにあると思います。また、それがその定義によって不明であるかどうかわからないので、それはそのオブジェクトのまわりのあいまいさを取り除くことを意味します。上記のAshleyの答えと同じように、それを何も含まない可能性があるプレゼントとして考えてください。しかし、アンラッピングは、コードのアンラッピングであり、enumを使用した場合のメモリベースのアンラッピングではないと思います。

126
Amr

TL、DR

Swift言語で感嘆符はどういう意味ですか?

感嘆符は効果的にこう言います。これは、オプションの値の強制的な展開として知られています。

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

出典: https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//Apple_ref/doc/uid/TP40014097-CH5-XID_399

65
Alex Nolasco

Johnがオプションのvarの場合(このように宣言されています)

var john: Person?

その場合、johnには値がない可能性があります(ObjCの用語では、nil値)。

感嘆符は基本的に「これには価値があることを知っているので、テストする必要はない」とコンパイラに伝えます。使用したくない場合は、条件付きでテストすることができます。

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

この内部は、johnに値があるかどうかを評価するだけです。

37
Ben Gottlieb

他の有用だが詳細中心の答えに追加するいくつかの全体像:

Swiftでは、感嘆符はいくつかのコンテキストで表示されます。

  • 強制アンラップ:let name = nameLabel!.text
  • 暗黙的にラップされていないオプション:var logo: UIImageView!
  • 強制キャスト:logo.image = thing as! UIImage
  • 未処理の例外:try! NSJSONSerialization.JSONObjectWithData(data, [])

これらはすべて、異なる意味を持つ異なる言語構成体ですが、すべてに共通する3つの重要なことがあります。

1.感嘆符は、Swiftのコンパイル時の安全性チェックを回避します。

Swiftで!を使用するとき、あなたは本質的に、「ねえ、コンパイラ、ここでエラーcouldが起こると思いますが、私はknow合計でそれは決してないという確実性。」

すべての有効なコードが、Swiftのコンパイル時型システムのボックスに収まるわけではありません。つまり、any言語の静的型のチェックです。エラーが発生しないことを論理的に証明できる場合もありますが、それを証明することはできませんコンパイラーに対して。 Swiftのデザイナーがこれらの機能をそもそも追加した理由です。

ただし、!を使用する場合は常に、エラーの回復パスを除外することになります。つまり、…

2.感嘆符は潜在的なクラッシュです。

また、感嘆符は、「ちょっとスウィフト、私はsoこのエラーは決して起こらないことを確信しています。あなたにとってはアプリ全体をクラッシュさせる回復パスをコーディングしてください。」

それは危険な主張です。それはcan正しいものです。コードの不変式についてよく考えているミッションクリティカルなコードでは、偽の出力はクラッシュよりも悪い可能性があります。

ただし、!が野生で表示されている場合、あまり気にしないで使用されることはほとんどありません。代わりに、「この値はオプションであり、why nilであるか、その状況を適切に処理する方法についてはあまり考えていなかったが、!それはコンパイルします...それで私のコードは正しいでしょう?」

感嘆符の慢に注意してください。代わりに…

3.感嘆符は慎重に使用するのが最適です。

これらの!コンストラクトには、エラー[nil]ケースを処理することを強制する?に対応するものがあります。

  • 条件付きアンラップ:if let name = nameLabel?.text { ... }
  • オプション:var logo: UIImageView?
  • 条件付きキャスト:logo.image = thing as? UIImage
  • 失敗時の例外:try? NSJSONSerialization.JSONObjectWithData(data, [])

!を使用したい場合は、代わりに?を使用しない理由を慎重に検討することをお勧めします。 !操作が失敗した場合、プログラムのクラッシュは本当に最適なオプションですか? その値がオプション/失敗する理由は何ですか?

あなたのコードがゼロ/エラーの場合に取ることができる合理的な回復パスはありますか?もしそうなら、それをコーディングします。

エラーが発生しない可能性がある場合、エラーが発生しない場合、コンパイラがそれを認識できるようにロジックを修正する合理的な方法はありますか?もしそうなら、それを行います。コードのエラーが発生しにくくなります。

エラーを処理する合理的な方法がなく、単にエラーを無視する場合があります。したがって、誤ったデータを処理する場合は、クラッシュするよりもworseになります。 Thoseは、強制アンラップを使用する時間です。

私は定期的にコードベース全体で!を検索し、その使用をすべて監査します。精査に耐える使用法はほとんどありません。 (この記事の執筆時点では、Siestaフレームワーク全体に twoinstances が含まれています。)

neverコードで!を使用する必要があると言うわけではありません。使用するだけでmindfullyにして、デフォルトオプションにしないでください。

27
Paul Cantrell

johnはオプションのvarです。 nilの値を含めることができます。値がnilではないことを確認するには、varの名前の最後に!を使用します。

ドキュメンテーションから

"オプションに値が含まれていることを確認したら、オプションの名前の末尾に感嘆符(!)を追加して、基になる値にアクセスできます。感嘆符は効果的にこう言います。それを使ってください。」

Nil以外の値をチェックする別の方法は

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

ここではいくつかの例を示します。

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

Wordはオプションの値です。値を含んでも含まなくてもよいことを意味します。

Word = name 

ここでnameは値を持つので、それを割り当てることができます。

var cow:String = nil
var dog:String!

dogが強制的にアンラップされている場合は、値が含まれている必要があることを意味します

dog = cow

nilをunwrappedに代入しているのでアプリケーションはクラッシュします

16

この場合...

varジョン:人!

つまり、最初はジョンはゼロ値を持ち、それが設定され、一度設定された値が二度とゼロになることはありません。したがって、便宜上、オプションのvarにアクセスするための簡単な構文を使用できます。これは「暗黙的にラップされていないオプション」だからです。

14
guest

C系の言語から来た人であれば、「メモリアドレス0(NULL)かもしれないX型のオブジェクトへのポインタ」と考えるでしょう。そして動的に型付けされた言語から来た人は、 「おそらくX型だが未定義型かもしれないオブジェクト」という考え。どちらも実際には正しいわけではありませんが、ラウンドアバウトでは最初のものが近いです。

あなたがそれについて考えるべきである方法はまるでそれがのような物であるかのようです:

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

あなたがfoo == nilであなたのオプションの値をテストしているとき、それは本当にfoo.isNilを返します、そして、あなたがfoo!を言うとき、それはfoo.realObjectというアサーションでfoo.isNil == falseを返します。 foo!を実行するときにfooが実際にnilである場合、それは実行時エラーであるため、値がnilにならないことが確実でない限り、通常は代わりに条件付きletを使用することをお勧めします。この種のトリックルは、値が至るところでゼロであるかどうかをテストすることを強いることなく、言語を強く型付けできることを意味します。

実際には、そのようには動作しません。作業はコンパイラによって行われるためです。高レベルではFooとは別のタイプFoo?があり、それはタイプFooを受け入れるfuncがnil値を受け取るのを防ぎますが、低レベルではオプションまたは値はプロパティもメソッドも持たないので真のオブジェクトではありません;実際には、強制的にアンラッピングするときに適切なテストでNULL(0)になる可能性があるポインタである可能性があります。

次のように、感嘆符がタイプに表示される状況が他にもあります。

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

これは、強制的に展開してオプションを受け入れるのとほぼ同じです。

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

これを使用して、技術的にオプションの値を受け入れるメソッドを持つことができますが、それがnilであればランタイムエラーを起こします。 Swiftの現在のバージョンでは、これは明らかにis-not-nilアサーションをバイパスしているので、代わりに低レベルのエラーが発生します。一般的には良い考えではありませんが、他の言語のコードを変換するときに役立ちます。

4
Jim Driscoll

C#に精通しているなら、これは疑問符を使って宣言されているNullable型のようなものです。

Person? thisPerson;

この場合の感嘆符は、次のようにnull許容型の.Valueプロパティにアクセスするのと同じです。

thisPerson.Value
3
Abdurrahman

です!それはあなたがそのオブジェクトを強制的に展開するということです。続きます。より多くの情報はここで見つけることができるりんごのドキュメンテーションで見つけることができます: https://developer.Apple.com/library/ios/documentation/Swift /コンセプト/ Swift_Programming_Language/TheBasics.html

Objective Cでは、値のない変数は 'nil'に等しくなりました(0やfalseと同じ 'nil'値を使うこともできました)。そのため、条件文で変数を使うことができました'と値がないものは' FALSE 'と同じです。

Swiftは「オプションの値」を提供することによって型の安全性を提供します。すなわち、異なるタイプの変数を代入することによって生じるエラーを防止します。

そのため、Swiftでは、条件文にはブール値のみを指定できます。

var hw = "Hello World"

ここで、 'hw'は文字列ですが、Objective Cのようにif文では使用できません。

//This is an error

if hw

 {..}

そのためには、次のように作成する必要があります。

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}
2
Gokul

簡単に言えば(!):変数を宣言した後で、その変数が値を保持していると確信していることを確認した後です。

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

それ以外の場合は、値を渡した後に毎回これを実行する必要があります。

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

です!オブジェクトの最後には、そのオブジェクトはオプションであり、それ以外の場合はnilを返すことができる場合は展開するように指示されています。これは、プログラムをクラッシュさせる可能性のあるエラーをトラップするためによく使用されます。

2
cheborneck

Optional変数は値を含んでいてもいなくてもかまいません

ケース1:var myVar:String? = "Something"

ケース2:var myVar:String? = nil

myVar!に尋ねると、ケース1では値を返すようにコンパイラに指示しているので、"Something"が返されます。

ケース2ではクラッシュします。

意味します。マークがない場合でも、markはコンパイラに値を返すよう強制します。それが、 Unwrappingを強制する の理由です。

1
Ashish Pisey

あなたがオプションとしてそれを使うならば、それはオプションをアンラップして、何かがあるかどうかを見ます。 if-else文で使用するのはNOTのコードです。例えば、

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

簡単に言うと、感嘆符はオプションがラップされていないことを意味します。オプションは、値を持つことができるかどうかにかかわらず、変数です。したがって、if let文 ここに示すように を使用して、変数が空かどうかを確認してから展開することができます。空のオプションをアンラップすると、プログラムがクラッシュしますので注意してください。オプションへの代入は、変数への明示的な代入の最後に疑問符を付けることによって宣言されます。例えば、

var optionalExample: String?

この変数には値がありません。アンラップするとプログラムがクラッシュし、Xilがあなたにnilの値でオプションをアンラップしようとしたことを教えてくれるでしょう。

お役に立てば幸いです。

1
brimstone

単純な言葉で

USING感嘆符は、変数がNULL以外の値で構成されている必要があることを示します(NULLになることはありません)

1

ストーリー全体は、オプションのvarsと呼ばれるSwiftの機能から始まります。これらは値を持っていてもいなくてもよいvarです。一般にSwiftは初期化されていない変数を使用することを許可していません。これはクラッシュや予期せぬ理由につながり、またバックドア用のプレースホルダーを提供する可能性があるためです。したがって、最初に値が決定されていない変数を宣言するために、 '?'を使用します。そのような変数が宣言されたとき、それを何らかの式の一部として使用するために使用する前にそれらをアンラップしなければならない、アンラップは変数の値が発見される操作です。それらを使用しようとすると、展開しないでコンパイル時エラーが発生します。オプションのvarである変数のラップを解除するには、感嘆符 "!"を使用します。使用されている。

疑問符 "?"を使用してオプションの変数を宣言するのではなく、そのような状況では、そのようなオプションの変数にシステムや独自のプログラムなどで値を代入することがあります。を使用しております "!"。

このようにシステムは "!"で宣言されているこの変数を知っています。現時点ではオプションであり、値はありませんが、ライフタイムの後半に値を受け取ります。

したがって、感嘆符には2つの異なる用途があります。1.オプションになり、後で確実に値を受け取る変数を宣言するため。2.式で使用する前にオプション変数のラップを解除するため。

上記の説明では、あまりにも多くの技術的なことを避けています。

1

JohnはオプションのPersonです。つまり、値を保持することも、nilにすることもできます。

john.apartment = number73

johnがオプションではない場合に使用されます。ジョンは決してnilではないので、我々はそれがnil値でアパートメントを呼び出さないことを確認することができます。しながら

john!.apartment = number73

johnがnilではないことをコンパイラに約束してから、johnの値を取得するためのオプションをアンラップし、johnのアパートのプロパティにアクセスします。あなたがジョンがゼロではないことを知っているなら、これを使ってください。これをnilオプションで呼び出すと、ランタイムエラーになります。

ドキュメントには、これを使用するためのNiceの例が含まれています。ここで、ConvertNumberはオプションです。

if convertedNumber {
    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}
1
Connor
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
0
jeff ayan