私はSwiftのオプションについて読んでいて、 if let
、オプションが値を保持しているかどうかをチェックするために使用される。
ただし、Swift 2.0ではキーワードguard let
が主に使用されていることを確認しました。if let
Swift 2.0から削除されたのか、それともまだ使えるのか。
を含むプログラムをに変更する必要if let
がありguard let
ますか?
私はSwiftのオプションについて読んでいて、 if let
、オプションが値を保持しているかどうかをチェックするために使用される。
ただし、Swift 2.0ではキーワードguard let
が主に使用されていることを確認しました。if let
Swift 2.0から削除されたのか、それともまだ使えるのか。
を含むプログラムをに変更する必要if let
がありguard let
ますか?
回答:
if let
そして、guard let
似ていますが異なる目的を果たします。
の「else」の場合はguard
、現在のスコープを終了する必要があります。一般的にはreturn
、プログラムを呼び出すか中止する必要があります。guard
関数の残りの入れ子を必要とせずに早期復帰を提供するために使用されます。
if let
スコープをネストし、特別なものを必要としません。それはできるreturn
かどうか。
一般に、if-let
ブロックが関数の残りの部分になる場合、またはそのelse
句にa return
またはabortが含まれる場合は、guard
代わりに使用する必要があります。これは多くの場合、(少なくとも私の経験では)疑わしい場合guard
は通常、より良い答えです。しかし、if let
それでも適切な状況はたくさんあります。
guard
エラーがなくても適切な場合が多くあります。時々、それは何もする必要がないことを意味します。たとえば、positionTitle
メソッドは次のようになりguard if let title = title else {return}
ます。タイトルは省略可能ですが、その場合はエラーではありません。しかしguard let
、それでも適切です。
if let
は、スコープ内 でのみ表示されif let
ます。バインドされた変数guard let
は後で表示されます。したがって、オプションの値をバインドするためにガードを使用することも理にかなっています。
ガードを使用すると、ガードが成功する可能性がはるかに高くなります。成功しない場合は、スコープを早期に終了することが重要です。配列がEmptyかどうかにかかわらず、ファイル/イメージが存在するかどうかを監視するように。
func icon() -> UIImage {
guard let image = UIImage(named: "Photo") else {
return UIImage(named: "Default")! //This is your fallback
}
return image //-----------------you're always expecting/hoping this to happen
}
上記のコードをif-letで記述した場合、それは50〜50程度であることが開発者に伝わります。しかし、ガードを使用する場合は、コードに明快さを追加し、95%の確率でこれが機能することを期待していることを意味します。それは非常にありそうにありません...しかし、代わりにこのデフォルトの画像を使用するか、おそらく何が問題かを説明する意味のあるメッセージでアサートしてください!
guard
副作用が生じる場合はを避けてください。ガードは自然な流れとして使用されます。else
句によって副作用が生じる場合は、ガードを避けてください。ガードはコードが適切に実行されるために必要な条件を確立し、早期終了を提供します正の分岐で重要な計算を実行するとき、from
if
をguard
ステートメントにリファクタリングし、else
句の フォールバック値を返しますFrom: エリカサドゥンのスウィフトスタイルブック
また、上記の提案とクリーンなコードの結果として、失敗したガードステートメントにアサーションを追加する必要がある可能性が高くなり、読みやすさが向上し、期待していたことが他の開発者に明確になります。
guard let image = UIImage(named: selectedImageName) else { // YESSSSSS assertionFailure("Missing \(selectedImageName) asset") return } guard let image = UIImage(named: selectedImageName) else { // NOOOOOOO return }
From: エリカサドゥンのスウィフトスタイルブック +いくつかの変更
(if-let
sのアサート/前提条件は使用しません。正しくないようです)
ガードを使用すると、運命のピラミッドを回避することにより、明快さを向上させることもできます。Nitinの回答を参照してください。
誰もうまく説明していないと私が信じている重要な違いが1つあります。
ただし、両方とも変数guard let
をif let
アンラップします
guard let
あなたが作成しているだろう、新たな変数が存在するの外にelse
声明を。
ではif let
、あなたが作成されていないすべての新しい可変後else文を、あなただけの入力したコードブロックを場合は、オプションが非nilです。新しく作成された変数は、コードブロック内にのみ存在します。
guard let:
func someFunc(blog: String?) {
guard let blogName = blog else {
print("some ErrorMessage")
print(blogName) // will create an error Because blogName isn't defined yet
return
}
print(blogName) // You can access it here ie AFTER the guard statement!!
//And if I decided to do 'another' guard let with the same name ie 'blogName' then I would create an error!
guard let blogName = blog else { // errorLine: Definition Conflicts with previous value.
print(" Some errorMessage")
return
}
print(blogName)
}
if-let:
func someFunc(blog: String?) {
if let blogName1 = blog {
print(blogName1) // You can only access it inside the code block. Outside code block it doesn't exist!
}
if let blogName1 = blog { // No Error at this line! Because blogName only exists inside the code block ie {}
print(blogName1)
}
}
詳細についてif let
は、「オプションのバインディングを再宣言してもエラーが発生しない理由」を参照してください。
(Rob Napierの回答にも記載されています):
func 内でguard
定義しておく必要があります。主な目的は、条件が満たされない場合にスコープを中止/返却/終了することです。
var str : String?
guard let blogName1 = str else {
print("some error")
return // Error: Return invalid outside of a func
}
print (blogName1)
if let
あなたはどのFUNC内側に持っている必要はありません。
var str : String?
if let blogName1 = str {
print(blogName1) // You don't get any errors!
}
guard
対 if
この質問をguard let
vs if let
およびguard
vs として見る方が適切であることは注目に値しif
ます。
スタンドアロンif
はアンラップを行わず、スタンドアロンも行いませんguard
。以下の例を参照してください。値がの場合、早期終了しませんnil
。オプションの値はありません。条件が満たされない場合は、ただちに終了します。
let array = ["a", "b", "c"]
func subscript(at index: Int) -> String?{
guard index > 0, index < array.count else { return nil} // exit early with bad index
return array[index]
}
いつ使用するかif-let
、いつ使用するかguard
は、しばしばスタイルの問題です。
たとえばfunc collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
、アイテムのオプションの配列(var optionalArray: [SomeType]?
)があり0
、配列がnil
(設定されていない)かcount
、配列に値が設定されている(設定されている)かのいずれかを返す必要があるとします。
次のようにして、このように実装できますif-let
。
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
if let array = optionalArray {
return array.count
}
return 0
}
またはこれを使用してこれを好きになるguard
:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
guard let array = optionalArray else {
return 0
}
return array.count
}
例は機能的に同じです。
どこ guard
あなたがデータを検証などのタスクを持っている、とあなたは何が間違っている場合、関数は早期に失敗したいときには本当に輝いています。
if-let
検証の終了に近づくと、一連のs をネストする代わりに、「成功パス」と現在正常にバインドされたオプションはすべて、メソッドのメインスコープにあります。これは、失敗パスがすべて返されているためです。
いくつかの(最適化されていない)コードを使用して、ガードステートメントの有用性を説明します。
姓、名、電子メール、電話番号、パスワードを使用してユーザー登録するためのテキストフィールドを検証するUIがあります。
textFieldに有効なテキストが含まれていない場合は、そのフィールドをfirstResponderにする必要があります。
ここに最適化されていないコードがあります:
//pyramid of doom
func validateFieldsAndContinueRegistration() {
if let firstNameString = firstName.text where firstNameString.characters.count > 0{
if let lastNameString = lastName.text where lastNameString.characters.count > 0{
if let emailString = email.text where emailString.characters.count > 3 && emailString.containsString("@") && emailString.containsString(".") {
if let passwordString = password.text where passwordString.characters.count > 7{
// all text fields have valid text
let accountModel = AccountModel()
accountModel.firstName = firstNameString
accountModel.lastName = lastNameString
accountModel.email = emailString
accountModel.password = passwordString
APIHandler.sharedInstance.registerUser(accountModel)
} else {
password.becomeFirstResponder()
}
} else {
email.becomeFirstResponder()
}
} else {
lastName.becomeFirstResponder()
}
} else {
firstName.becomeFirstResponder()
}
}
上記のとおり、すべての文字列(firstNameString、lastNameStringなど)には、ifステートメントのスコープ内でのみアクセスできます。そのため、この「運命のピラミッド」が作成され、可読性や移動のしやすさなど、多くの問題があります(フィールドの順序が変更された場合は、このコードのほとんどを書き直す必要があります)
(以下のコードの)ガードステートメントを{}
使用すると、すべてのフィールドが有効な場合に、これらの文字列がの外部で使用可能であり、使用されていることがわかります。
// guard let no pyramid of doom
func validateFieldsAndContinueRegistration() {
guard let firstNameString = firstName.text where firstNameString.characters.count > 0 else {
firstName.becomeFirstResponder()
return
}
guard let lastNameString = lastName.text where lastNameString.characters.count > 0 else {
lastName.becomeFirstResponder()
return
}
guard let emailString = email.text where
emailString.characters.count > 3 &&
emailString.containsString("@") &&
emailString.containsString(".") else {
email.becomeFirstResponder()
return
}
guard let passwordString = password.text where passwordString.characters.count > 7 else {
password.becomeFirstResponder()
return
}
// all text fields have valid text
let accountModel = AccountModel()
accountModel.firstName = firstNameString
accountModel.lastName = lastNameString
accountModel.email = emailString
accountModel.password = passwordString
APIHandler.sharedInstance.registerUser(accountModel)
}
フィールドの順序が変更された場合は、それぞれのコード行を上下に移動するだけで問題ありません。
これは非常に単純な説明であり、使用例です。お役に立てれば!
私が見た最も明確な説明は、Github Swift Style Guideにありました:
if
深さのレベルを追加します。
if n.isNumber {
// Use n here
} else {
return
}
guard
しない:
guard n.isNumber else {
return
}
// Use n here
guard
1つ以上の条件が満たされていない場合のステートメントは、スコープの外に転送プログラム制御に使用されています。
guard
ステートメント内の条件の値は、タイプBool
またはブリッジされるタイプである必要がありますBool
。条件は、オプションのバインディング宣言にすることもできます。
ガードステートメントの形式は次のとおりです。
guard condition else {
//Generally return
}
- オプションのバインディングとしても人気があります。
- オプションのオブジェクトにアクセスするには、を使用します
if let
。
if let roomCount = optionalValue {
print("roomCount available")
} else {
print("roomCount is nil")
}
私はこれをボブと一緒に素早く学んだ。
典型的なElse-If
func checkDrinkingAge() {
let canDrink = true
if canDrink {
print("You may enter")
// More Code
// More Code
// More Code
} else {
// More Code
// More Code
// More Code
print("Let me take you to the jail")
}
}
Else-Ifの問題
ガードステートメント ガードブロックは、条件がfalseの場合にのみ実行され、リターンによって関数から抜けます。条件が真の場合、Swiftはガードブロックを無視します。それは早期の終了とより少ない括弧を提供します。+
func checkDrinkProgram() {
let iCanDrink = true
guard iCanDrink else {
// if iCanDrink == false, run this block
print("Let's me take you to the jail")
return
}
print("You may drink")
// You may move on
// Come on.
// You may leave
// You don't need to read this.
// Only one bracket on the bottom: feeling zen.
}
Else-Ifでオプションをアンラップ
ガードステートメントは、一般的な条件付きブロックをelse-ifステートメントで置き換えるのに役立つだけでなく、角かっこの数を最小限にしてオプションをアンラップするのにも最適です。比較のために、まず、else-ifを使用して複数のオプションをアンラップする方法から始めましょう。まず、アンラップされる3つのオプションを作成します。
var publicName: String? = "Bob Lee"
var publicPhoto: String? = "Bob's Face"
var publicAge: Int? = nil
最悪の悪夢
func unwrapOneByOne() {
if let name = publicName {
if let photo = publicPhoto {
if let age = publicAge {
print("Bob: \(name), \(photo), \(age)")
} else {
print("age is mising")
}
} else {
print("photo is missing")
}
} else {
print("name is missing")
}
}
上記のコードは確かに機能しますが、DRYの原則に違反しています。それはひどいです。分解してみましょう+。
少し良い 以下のコードは、上記よりも読みやすくなっています。+
func unwrapBetter() {
if let name = publicName {
print("Yes name")
} else {
print("No name")
return
}
if let photo = publicPhoto {
print("Yes photo")
} else {
print("No photo")
return
}
if let age = publicAge {
print("Yes age")
} else {
print("No age")
return
}
}
Guardでアンラップ else-ifステートメントをguardで置き換えることができます。+
func unwrapOneByOneWithGuard() {
guard let name = publicName else {
print("Name missing")
return
}
guard let photo = publicPhoto else {
print("Photo missing")
return
}
guard let age = publicAge else {
print("Age missing")
return
}
print(name)
print(photo)
print(age)
}
Else-Ifを使用して複数のオプションをアンラップする これまで、オプションを1つずつアンラップしてきました。Swiftを使用すると、複数のオプションを一度にアンラップできます。それらのいずれかにnilが含まれている場合は、elseブロックが実行されます。
func unwrap() {
if let name = publicName, let photo = publicPhoto, let age = publicAge {
print("Your name is \(name). I see your face right here, \(photo), you are \(age)")
} else {
// if any one of those is missing
print("Something is missing")
}
}
一度に複数のオプションを展開すると、nilを含むものを特定できないことに注意してください
ガードを使用して複数のオプションをアンラップするもちろん、else-ifの場合はガードを使用する必要があります。+
func unwrapWithGuard() {
guard let name = publicName, let photo = publicPhoto, let age = publicAge else {
// if one or two of the variables contain "nil"
print("Something is missing")
return
}
print("Your name is \(name). I see your, \(photo). You are \(age).")
// Animation Logic
// Networking
// More Code, but still zen
}
if let
しnon-nil
ます。ケースが何らかのエラーを表す場合に使用guard
しnil
ます。