2017-04-09 15 views
21

Sau khi tìm kiếm một số tài liệu tham khảo để tìm ra, tôi không thể tìm thấy mô tả hữu ích và đơn giản về sự khác biệt giữa throwsrethrows. Nó là loại khó hiểu khi cố gắng hiểu làm thế nào chúng ta nên sử dụng chúng.Sự khác nhau giữa ném và rethrows trong Swift là gì?

tôi sẽ đề cập đến rằng tôi loại quen thuộc với -default- throws với dạng đơn giản nhất để tuyên truyền một lỗi như sau:

enum CustomError: Error { 
    case potato 
    case tomato 
} 

func throwCustomError(_ string: String) throws { 
    if string.lowercased().trimmingCharacters(in: .whitespaces) == "potato" { 
     throw CustomError.potato 
    } 

    if string.lowercased().trimmingCharacters(in: .whitespaces) == "tomato" { 
     throw CustomError.tomato 
    } 
} 

do { 
    try throwCustomError("potato") 
} catch let error as CustomError { 
    switch error { 
    case .potato: 
     print("potatos catched") // potatos catched 
    case .tomato: 
     print("tomato catched") 
    } 
} 

Cho đến nay rất tốt, nhưng vấn đề nảy sinh khi:

func throwCustomError(function:(String) throws ->()) throws { 
    try function("throws string") 
} 

func rethrowCustomError(function:(String) throws ->()) rethrows { 
    try function("rethrows string") 
} 

rethrowCustomError { string in 
    print(string) // rethrows string 
} 

try throwCustomError { string in 
    print(string) // throws string 
} 

những gì tôi biết cho đến nay là khi gọi một hàm throws nó phải được xử lý bởi một try, không giống như các rethrows. Vậy cái gì ?! Logic mà chúng ta nên làm theo khi quyết định sử dụng throws hoặc rethrows là gì?

Trả lời

57

Từ "Declarations" trong cuốn sách Swift:

Chức năng rethrowing và phương pháp

Một chức năng hoặc phương pháp có thể được khai báo với từ khóa rethrows để chỉ ra rằng nó ném một lỗi chỉ khi một trong những chức năng của nó là thông số ném lỗi. Các hàm và phương thức này được gọi là chức năng làm lạiphương pháp làm lại. Các hàm rethrowing và các phương thức phải có ít nhất một tham số hàm ném.

Một ví dụ điển hình là map phương pháp:

public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T] 

Nếu map được gọi với một tổ chức phi ném biến đổi, nó không ném một lỗi bản thân và có thể được gọi mà không try:

// Example 1: 

let a = [1, 2, 3] 

func f1(n: Int) -> Int { 
    return n * n 
} 

let a1 = a.map(f1) 

Nhưng nếu map được gọi với một đóng cửa ném thì chính nó có thể ném một d phải được gọi với try:

// Example 2: 

let a = [1, 2, 3] 
enum CustomError: Error { 
    case illegalArgument 
} 

func f2(n: Int) throws -> Int { 
    guard n >= 0 else { 
     throw CustomError.illegalArgument 
    } 
    return n*n 
} 


do { 
    let a2 = try a.map(f2) 
} catch { 
    // ... 
} 
  • Nếu map được khai báo là throws thay vì rethrows sau đó bạn sẽ phải gọi nó với try ngay cả trong ví dụ 1, đó là "bất tiện" và bloats mã không cần thiết.
  • Nếu map được khai báo mà không có throws/rethrows thì bạn không thể gọi nó bằng cách đóng cửa ném như trong ví dụ 2.

Điều này cũng đúng đối với các phương pháp khác từ Swift thư viện chuẩn mà lấy thông số chức năng: filter(), index(where:), forEach() và nhiều nhiều hơn nữa.

Trong trường hợp của bạn,

func throwCustomError(function:(String) throws ->()) throws 

biểu thị một chức năng mà có thể ném một lỗi, ngay cả khi được gọi với một cuộc tranh luận không ném, trong khi

func rethrowCustomError(function:(String) throws ->()) rethrows 

biểu thị một chức năng mà ném một lỗi chỉ khi được gọi với một đối số ném .

Nói một cách khái quát, rethrows là dành cho các chức năng không tự ném lỗi "nhưng chỉ" chuyển tiếp "lỗi từ các tham số chức năng của chúng.

+1

Câu trả lời hay. Cảm ơn. – Darko

+3

Câu cuối cùng là vàng! – Klaas

+1

vì vậy tôi đoán tổng hợp nó, 'rethrow' khi bạn * có thể * muốn ném. 'ném' khi bạn muốn ** hạn chế để luôn ** ném – Honey

7

Chỉ cần thêm điều gì đó cùng với câu trả lời của Martin. Hàm không ném có cùng chữ ký với chức năng ném được coi là sub-type của hàm ném. Đó là lý do tại sao rethrows có thể xác định nó là gì và chỉ yêu cầu try khi tham số func cũng ném, nhưng vẫn chấp nhận cùng một chữ ký hàm không ném. Đó là một cách thuận tiện để chỉ phải sử dụng khối try khi func param throws, nhưng mã khác trong hàm không ném một lỗi.

Các vấn đề liên quan