Swift IF LET ได้รับการประเมินอย่างไร


90

ฉันเคยเห็นรหัสนี้ในไซต์ Swift และโพสต์ต่างๆที่นี่และฉันกำลังพยายามทำความเข้าใจพื้นฐาน สายงานนี้ได้รับการประเมินอย่างไร?

if let name = optionalName {

ฉันสับสนเพราะมันไม่ใช่ name == ชื่อทางเลือกมันกำลังกำหนดค่าดังนั้นรายงานนั้นเป็นจริงได้อย่างไรและทำไมจึงไม่เป็นความจริงเมื่อคุณแทนที่ด้วย john appleseed ด้วย nil เนื่องจากมันจะยังคงเท่ากัน

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}

10
ค้นหา "การผูกแบบเลือกได้" ในเอกสาร Swift ...
Martin R

3
รายละเอียดดูที่ optionals ที่dev.iachieved.it/iachievedit/?p=314ที่if letไวยากรณ์เป็นที่รู้จักกันเป็นตัวเลือกที่มีผลผูกพัน
โจ

คำตอบ:


105

โดยพื้นฐานแล้วบรรทัดจะบอกว่า "ถ้าคุณปล่อยให้ตัวแปรใหม่nameเท่ากับเวอร์ชันที่ไม่เป็นทางเลือกoptionalNameให้ทำสิ่งต่อไปนี้ด้วย" มาร์ตินชี้ให้เห็นนี้เรียกว่าเป็นตัวเลือกที่มีผลผูกพัน

จุดประสงค์เดียวของมันคือการทดสอบว่าตัวแปรทางเลือกมีค่าจริงหรือไม่และผูกรูปแบบที่ไม่ใช่ทางเลือกเข้ากับตัวแปรชั่วคราว นี่เป็นวิธีที่ปลอดภัยในการ "แกะ" ตัวเลือกหรืออีกนัยหนึ่งคือเข้าถึงค่าที่อยู่ในตัวเลือก ไม่มีการทดสอบความเท่าเทียมกันใด ๆ ทั้งสิ้น เป็นการทดสอบการมีอยู่ของค่าภายในตัวเลือกเท่านั้น


2
ฉันจะอ่านเรื่องนั้นเมื่อฉันลงไปฉันเพิ่งเริ่มบทนำอย่างรวดเร็วและมันไม่ได้อธิบายมัน คำอธิบายของคุณสมเหตุสมผลดีขอบคุณ
DeadZero

1
ทำไมเราไม่ควรใช้ "! =" แทน "if let" เพื่อตรวจสอบว่าตัวแปรทางเลือกมีค่าเช่น - if optionalName! = nil {greeting = "Hello, (name)"}
Nuibb

4
@Nuibb เพราะเมื่อใช้if letเราผูกค่ากับตัวแปรที่ไม่ใช่ทางเลือก ( nameในตัวอย่างนี้) nameตัวอย่างของคุณจะไม่รวบรวมเพราะตอนนี้มีตัวแปรที่เรียกว่าไม่มี หากคุณเปลี่ยนตัวอย่างที่จะใช้optionalNameมันจะพิมพ์เป็นHello, Optional("John Appleseed")ไฟล์. คุณสามารถใช้การบังคับให้แกะออกหลังจากตรวจสอบกับศูนย์Hello, \(optionalName!)แต่นี่เป็นเพียงข้อผิดพลาดที่เกิดขึ้นได้ง่ายหากคุณย้ายส่วนของรหัสนั้นไปที่ไหนสักแห่งโดยไม่ต้องตรวจ
drewag

30

ตัวเลือกจะตั้งค่าหรือไม่ได้ตั้งค่า (ไม่ใช่ศูนย์หรือศูนย์) ... ปล่อยให้เรามีการตัดสินใจที่สำคัญ "เราควรเขียนโค้ดของเราอย่างไรเพื่อให้สามารถทำงานได้อย่างถูกต้องสำหรับ 2 สถานะทั้งสอง". วิธีที่เราแกะตัวเลือกคือสิ่งที่ตัดสินใจสำหรับเรา

มีหลายวิธีที่คุณสามารถใช้เพื่อตอบโต้ตัวเลือกที่ไม่ได้ตั้งค่า

  • พัง!
  • ตั้งค่าเริ่มต้นเป็นบางสิ่ง - หากไม่ได้ตั้งค่าไว้
  • ล้มเหลวอย่างสง่างามคือไม่ต้องทำอะไรเลย แต่ถ้าตั้งค่าแล้วให้กำหนดค่านั้น
  • ล้มเหลวอย่างสง่างามคือไม่ต้องทำอะไรเลยอย่างไรก็ตามหากตั้งค่า ... ทำบางสิ่งบางอย่าง (มันเป็นมากกว่าการมอบหมายงานเดียว)

ด้านล่างนี้คือ 4 แนวทาง


การใช้บังคับแกะกล่องจะขัดข้องหากคุณไม่มีค่า คุณจะต้องทำเช่นนี้หากค่านั้นมีความสำคัญอย่างยิ่งเช่นชื่อภาพยนตร์ (ภาพยนตร์ทุกเรื่องต้องมีชื่อ) !ใช้สำหรับบังคับแกะ

movieTitle = movie.title!

การใช้nil coalescingเป็นอีกวิธีหนึ่งที่จะช่วยให้คุณควบคุมได้มากขึ้นซึ่งหมายความว่าจะไม่ผิดพลาดหากไม่ได้ตั้งค่าและจะ 'ไม่ตั้งค่าอะไรเลย' หากไม่ได้ตั้งค่า ... มันจะทำตามที่คุณบอก ที่จะทำเช่นมันจะเริ่มต้น / ตั้งชื่อของภาพยนตร์เป็น untitled_movieหากไม่มีการตั้งชื่อ ??ใช้สำหรับการรวมกันเป็นศูนย์

var movieTitle = movie.title ?? "untitled_Movie"

การใช้Chaining เสริมจะไม่ทำอะไรเลยหากคุณไม่มีค่าและจะกำหนดค่าหากคุณมีค่า คุณทำสิ่งนี้เพื่อบางสิ่งบางอย่างที่การกำหนดค่าของมันไม่ได้มีความสำคัญอย่างยิ่งเช่นการตั้งชื่อตัวแทนนักแสดงของคุณ ?ใช้สำหรับโซ่เสริม

let agent = movie.leadActor?.agent //would not crash if you don't have a lead actor (optional chaining)
let agent = movie.leadActor!.agent //would crash if you don't have a lead Actor (forced wrapping)  

การใช้if-let(หรือการเชื่อมโยงที่เป็นทางเลือกguardสองประเภทที่แตกต่างกัน) จะทำให้คุณควบคุมได้มากขึ้นและจะไม่ผิดพลาดหากไม่ได้ตั้งค่าไว้ หากตั้งค่าแล้วคุณสามารถทำบางสิ่งได้ หากยังไม่ได้ตั้งค่าคุณสามารถเพิ่มคำสั่งได้else

if let supportingActor = movie.supportingActor{
print(" The supporting actor is \(supportingActor)}

นี่เป็นวิธีการแกะที่ใช้กันมากที่สุดเนื่องจากการบังคับให้แกะห่อค่อนข้างไม่ดี สำหรับการอภิปรายเพิ่มเติมเกี่ยวกับเหตุผลที่มันเป็นกำลังใจดูที่นี่ สำหรับการเปรียบเทียบที่ดีระหว่างguardและif-letดูguard vs. if-let


หมายเหตุด้านข้าง:

โดยทั่วไปจะใช้การผูกเสริมและการผูกมัดเสริมร่วมกัน:

if let agent = movie.leadActor?.agent {
ContactInfo = agent.phoneNumber
} // if-let is the optional *binding* part, the movie dot leadActor dot is the optional *chaining*
 

เหตุใดการบังคับให้คลายการห่อจึงถูกกีดกันเนื่องจากสถานการณ์ที่ movieTitle ไม่สามารถเป็นอย่างอื่นได้นอกจากสตริงและสตริงทั้งหมดใช้ได้กับ movieTitle (และฉันไม่ต้องการ "ภาพยนตร์ที่ไม่มีชื่อ" ฉันต้องการ ") การบังคับให้แกะเป็นวิธีเดียวที่เหมาะสมสำหรับสถานการณ์นี้จะเป็นการดีมากหากคุณสามารถลบส่วนที่ระบุว่า .
Andy

สมมติว่าคุณทำการโทรผ่านเครือข่ายและผู้พัฒนาทีมเซิร์ฟเวอร์บางคนตัดสินใจไม่ถูกต้องและลืมส่งชื่อภาพยนตร์ คุณต้องการให้แอปของคุณขัดข้องในการใช้งานจริงหรือไม่? หรือเพียงแค่เขียนชื่อที่ไม่รู้จัก? ตามความเป็นจริงภาพยนตร์บางเรื่องใน IMDb ไม่มีชื่อเรื่อง :) นอกจากนี้การบังคับให้แกะหมายความว่าคุณยังไม่ได้ทำการบันทึกหรือยืนยันใด ๆ เลวร้าย. เพราะคุณจะไม่รู้ว่าต้นเหตุคืออะไร
น้ำผึ้ง

นั่นเป็นข้อโต้แย้งของมนุษย์ฟางฉันไม่เคยพูดว่า "ใช้การบังคับแกะเสมอ" เพียงเพราะคุณไม่ควรใช้การบังคับแกะในตัวอย่างของคุณไม่ได้หมายความว่าการบังคับให้แกะห่อจะหมดกำลังใจในทุกตัวอย่าง ฉันให้สถานการณ์แก่คุณซึ่งการบังคับให้แกะเป็นทางออกเดียวที่ถูกต้องจากสี่ข้อที่คุณนำเสนอ คุณสามารถให้ทางออกที่ดีกว่าสำหรับสถานการณ์ที่กล่าวถึงความคิดเห็นก่อนหน้าของฉันได้ไหม หากไม่เป็นเช่นนั้นโปรดพิจารณาแก้ไขความคิดเห็นของคุณเกี่ยวกับ "การบังคับให้แกะออกเป็นเรื่องที่ท้อใจอยู่บ้าง" เพราะไม่ควรท้อถอยโดยไม่พิจารณาบริบท
Andy

หากคุณผิดนัดบางอย่างเป็น“” ก็จะไม่ใช่ทางเลือกอีกต่อไป
น้ำผึ้ง

ตัวอย่างเช่นค่า "" นั้นมาจากคุณสมบัติข้อความของอินสแตนซ์ UILabel ที่สร้างในสตอรีบอร์ดซึ่งเป็นทางเลือกเนื่องจากอาจไม่มีค่าหากคุณสร้างแบบไดนามิก แต่ที่นี่คุณไม่ได้สร้างแบบไดนามิกดังนั้นจึงมีค่าสตริงเสมอ . คุณจะไม่ใช้การบังคับแกะกล่องในกรณีนี้ แต่คุณจะแกะ if-let และระบุค่าที่เหมือนกับค่าเริ่มต้น "" หรือไม่ คุณสามารถทำได้ แต่นั่นไม่มีจุดหมายไม่จำเป็นและเป็นเรื่องใหญ่ และจะเกิดอะไรขึ้นถ้าคุณใช้ไลบรารี HTTP ซึ่งจะส่งคืนพจนานุกรมเสมอแม้ว่าจะมีข้อผิดพลาดก็ตาม มันขึ้นอยู่กับบริบท
Andy

4

ไวยากรณ์ if ยอมรับ 2 เงื่อนไขที่แตกต่างกัน ประการที่สองการรวมทางเลือกไม่ใช่บูลีน สิ่งนี้สับสนอย่างที่คุณสามารถเขียนได้:

if let name = optionalName {

แต่ไม่

if (let name = optionalName) {

เอกสารของ Apple (ข้อมูลอ้างอิงอย่างรวดเร็ว):

ค่าของเงื่อนไขจะต้องเป็นชนิดBoolหรือประเภท bridged Boolไป เงื่อนไขนี้ยังสามารถเป็นการประกาศการผูกที่เป็นทางเลือกตามที่กล่าวไว้ในการผูกแบบเลือกได้


3

if ใช้เฉพาะนิพจน์บูลีนเท่านั้นนอกเหนือจากนั้นจะทำให้เกิดข้อผิดพลาดดังนั้นข้อมูลโค้ดนี้จึงบอกว่า

if let name = optionalName {

}else{

}

ถ้า optionalName เป็นศูนย์แสดงว่าเงื่อนไขเป็นเท็จและคำสั่งอื่นจะดำเนินการ อย่างไรก็ตามหาก optionalName มีค่าบางค่าค่าที่เป็นทางเลือกจะถูกคลาย / กำหนดให้กับตัวแปรคงที่เช่นชื่อ


1

เมื่อใดก็ตามที่คุณทำงานกับการอ้างอิงที่ไม่เหมาะสมประเภทที่เป็นทางเลือกจะดีกว่าหากปล่อยให้ป้องกันรหัสของคุณอย่างปลอดภัยและหลีกเลี่ยงข้อขัดข้องนี่คือตัวอย่าง

var middleName :String? = "some thing"
if let isExistsMiddleName = middleName {
// do some thing here
} else {
// no middle name
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.