cố gắng lên & thử? sự khác biệt là gì và khi nào nên sử dụng?


172

Trong Swift 2.0 , Apple đã giới thiệu một cách mới để xử lý lỗi (do-try-Catch). Và vài ngày trước trong Beta 6, một từ khóa thậm chí mới hơn đã được giới thiệu ( try?). Ngoài ra, biết rằng tôi có thể sử dụng try!. Sự khác biệt giữa 3 từ khóa và khi nào nên sử dụng mỗi từ khóa?

Câu trả lời:


316

Đã cập nhật cho Swift 5.1

Giả sử hàm ném sau:

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)
  }
}

thử

Bạn có 2 tùy chọn khi bạn thử gọi một chức năng có thể ném.

Bạn có thể chịu trách nhiệm xử lý lỗi bằng cách bao quanh cuộc gọi của mình trong khối chặn bắt:

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)
}

Hoặc chỉ cần thử gọi hàm và chuyển lỗi cho người gọi tiếp theo trong chuỗi cuộc gọi:

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

thử!

Điều gì xảy ra khi bạn cố gắng truy cập vào một tùy chọn ngầm được mở ra với một con số không bên trong nó? Vâng, đúng, ứng dụng sẽ CRASH! Cùng đi với thử! về cơ bản, nó bỏ qua chuỗi lỗi và tuyên bố một tình huống do do chết hoặc chết. Nếu hàm được gọi không ném bất kỳ lỗi nào, mọi thứ đều ổn. Nhưng nếu nó không thành công và gây ra lỗi, ứng dụng của bạn sẽ bị sập .

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

thử?

Một từ khóa mới được giới thiệu trong Xcode 7 beta 6. Nó trả về một tùy chọn hủy bỏ các giá trị thành công và bắt lỗi bằng cách trả về nil.

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

Hoặc chúng ta có thể sử dụng bảo vệ:

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

Một lưu ý cuối cùng ở đây, bằng cách sử dụng try?lưu ý rằng bạn đang loại bỏ lỗi xảy ra, vì nó được dịch thành con số không. Dùng thử? khi bạn tập trung nhiều hơn vào thành công và thất bại, không phải tại sao mọi thứ thất bại.

Sử dụng toán tử liên kết ??

Bạn có thể sử dụng toán tử liên kết ?? với thử không? để cung cấp một giá trị mặc định trong trường hợp thất bại:

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

Mẫu mã thứ hai của bạn ( let result = try doSomething() // Not within a do-catch block) sẽ được gọi từ bên trong một phương thức được khai báo là throws, phải không? Vì vậy, nếu doSomething()thất bại, thì phương thức bên ngoài cũng vậy (lần lượt)?
Nicolas Miari

Chủ đề cũ và tất cả nhưng tôi thấy rằng hôm nay (Swift 4, Xcode 9.1) thử? không tự động hủy kết quả. Nó chỉ để nó như một tùy chọn bình thường để bạn mở khóa bằng tay. Không chắc chắn nếu điều này thay đổi kể từ Swift 2/3 nhưng nó là theo tài liệu: developer.apple.com/l Library / content / documentation / Swift / Lỗi (xem Chuyển đổi lỗi thành giá trị tùy chọn ). Giải thích tuyệt vời về thử btw.
the_dude_abides

1
trong 4 nhanh, thử không? không loại bỏ các lệnh gọi chức năng ném xảy ra trong các biểu thức 'thử' trong dự án của tôi.
aznelite89

7
Bạn cũng có thể sử dụng try?với ??vì thế nó sẽ cho phép bạn xác định một giá trị mặc định trong một dòng:let something:String = (try? whateverIfItThrows()) ?? "Your default value here"
itMaxence
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.