ลองลอง! & ลอง? ความแตกต่างคืออะไรและจะใช้เมื่อใด


172

ในSwift 2.0 , Apple แนะนำวิธีใหม่ในการจัดการข้อผิดพลาด (do-try-catch) เมื่อไม่กี่วันที่ผ่านมาใน Beta 6 มีการใช้คำหลักที่ใหม่กว่า ( try?) try!นอกจากนี้ยังรู้ว่าฉันสามารถใช้ คำหลักทั้งสามคำแตกต่างกันอย่างไรและจะใช้เมื่อใด

คำตอบ:


316

อัปเดตสำหรับ Swift 5.1

สมมติว่าฟังก์ชั่นการขว้างปาต่อไปนี้:

enum ThrowableError: Error {

    case badError(howBad: Int)
}

func doSomething(everythingIsFine: Bool = false) throws -> String {

  if everythingIsFine {
      return "Everything is ok"
  } else {
      throw ThrowableError.badError(howBad: 4)
  }
}

ลอง

คุณมี 2 ตัวเลือกเมื่อคุณลองเรียกใช้ฟังก์ชันที่อาจมีการโยน

คุณสามารถรับผิดชอบในการจัดการข้อผิดพลาดโดยรอบการโทรของคุณภายในบล็อก do-catch:

do {
    let result = try doSomething()
}
catch ThrowableError.badError(let howBad) {
    // Here you know about the error
    // Feel free to handle or to re-throw

    // 1. Handle
    print("Bad Error (How Bad Level: \(howBad)")

    // 2. Re-throw
    throw ThrowableError.badError(howBad: howBad)
}

หรือเพียงแค่ลองเรียกใช้ฟังก์ชันและส่งข้อผิดพลาดไปยังผู้โทรรายถัดไปในเครือข่ายการโทร:

func doSomeOtherThing() throws -> Void {    
    // Not within a do-catch block.
    // Any errors will be re-thrown to callers.
    let result = try doSomething()
}

ลอง!

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

let result = try! doSomething() // if an error was thrown, CRASH!

ลอง?

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

if let result = try? doSomething() {
    // doSomething succeeded, and result is unwrapped.
} else {
    // Ouch, doSomething() threw an error.
}

หรือเราสามารถใช้ยาม:

guard let result = try? doSomething() else {
    // Ouch, doSomething() threw an error.
}
// doSomething succeeded, and result is unwrapped.

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

ใช้ตัวดำเนินการรวมกัน?

คุณสามารถใช้โอเปอเรเตอร์รวมตัวกันได้หรือไม่? ด้วยลอง? เพื่อให้ค่าเริ่มต้นกรณีของความล้มเหลว:

let result = (try? doSomething()) ?? "Default Value"
print(result) // Default Value

ตัวอย่างโค้ดที่สองของคุณ ( let result = try doSomething() // Not within a do-catch block) จะต้องถูกเรียกจากภายในวิธีการที่ประกาศว่าthrowsใช่ไหม ดังนั้นถ้าdoSomething()ล้มเหลววิธีการด้านนอกก็เช่นกัน (ในทางกลับกัน)?
Nicolas Miari

ด้ายเก่าและทั้งหมด แต่ฉันพบว่าวันนี้ (Swift 4, Xcode 9.1) ลอง? ไม่ได้แกะผลโดยอัตโนมัติ มันปล่อยให้มันเป็นตัวเลือกปกติสำหรับคุณที่จะแกะด้วยตนเอง ไม่แน่ใจว่าสิ่งนี้เปลี่ยนแปลงไปจาก Swift 2/3 หรือไม่ แต่เป็นไปตามเอกสาร: developer.apple.com/library/content/documentation/Swift/ ...... (ดูการแปลงข้อผิดพลาดเป็นค่าเสริม ) คำอธิบายที่ดีของการลอง btw
the_dude_abides

1
ใน swift 4 ลองไหม ไม่ลบฟังก์ชั่นการเรียกไปยังการขว้างปาในนิพจน์ 'ลอง' ในโครงการของฉัน
aznelite89

7
นอกจากนี้คุณยังสามารถใช้try?กับ??ดังนั้นมันจะช่วยให้คุณสามารถกำหนดค่าเริ่มต้นในหนึ่งบรรทัด:let something:String = (try? whateverIfItThrows()) ?? "Your default value here"
itMaxence
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.