[swift] Swift에서 throw와 rethrows의 차이점은 무엇입니까?

일부 참고 문헌을 검색 하시나요을 파악 후, 나는 사이의 차이를 이해에 대한 유용한 – 그리고 SIMPLE- 설명을 찾을 수 없습니다 -unfortunately- throwsrethrows. 우리가 그것들을 어떻게 사용해야하는지 이해하려고 할 때 다소 혼란 스럽습니다.

나는 throws다음과 같이 오류를 전파하는 가장 간단한 형식으로 -default-에 익숙하다고 언급하고 싶습니다 .

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

지금까지는 좋지만 문제는 다음과 같은 경우에 발생합니다.

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
}

하는 함수를 호출 할 때 내가 지금까지 알고있는 것은 throws그것이 의해 처리되어야한다 try달리 rethrows. 그래서 뭐?! throws또는 사용을 결정할 때 따라야 할 논리는 무엇입니까 rethrows?



답변

에서 “선언” 스위프트의 책 :

다시 던지는 기능 및 방법

함수 또는 메소드는 rethrows함수 매개 변수 중 하나가 오류를 발생시키는 경우에만 오류가 발생 함을 나타 내기 위해 키워드로 선언 될 수 있습니다 . 이러한 기능과 방법을 다시
던지기 기능 및 다시 던지기 방법이라고 합니다. 다시 던지는 함수와 메서드에는 던지는 함수 매개 변수가 하나 이상 있어야합니다.

일반적인 예는 다음과 map같습니다.

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

경우 map비 던지는 불려 그 자체를 오류가 발생하지 않으며없이 호출 할 수 있습니다, 변환 try:

// Example 1:

let a = [1, 2, 3]

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

let a1 = a.map(f1)

그러나 mapthrowing 클로저로 호출 되면 자체적으로 throw 될 수 있으며 다음과 같이 호출되어야합니다 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 {
    // ...
}
  • 대신에 map선언 된 경우 예제 1에서도 호출해야합니다 . 이는 “불편하고”코드를 불필요하게 부풀립니다.throwsrethrowstry
  • map없이 선언 된 경우 throws/rethrows예제 2에서와 같이 throwing 클로저로 호출 할 수 없습니다.

함수 매개 변수 filter()index(where:), forEach()등 을 사용하는 Swift Standard Library의 다른 메서드도 마찬가지입니다 .

귀하의 경우에는

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

던지지 않는 인수로 호출 되더라도 오류가 발생할 수있는 함수를 나타냅니다.

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

throwing 인수로 호출되는 경우에만 오류를 발생시키는 함수를 나타냅니다.

대략적으로 말하자면, rethrows“자체적으로”오류를 발생시키지 않고 함수 매개 변수에서 “전달”오류 만 발생시키는 함수를위한 것입니다.


답변

Martin의 대답과 함께 무언가를 추가하십시오. 던지는 함수와 동일한 시그니처를 가진 던지지 않는 함수는 던지는 함수로 간주 sub-type됩니다. 그렇기 때문에 rethrows는 그것이 무엇인지 결정할 수 try있고 func param도 throw 할 때만 필요 하지만 throw되지 않는 동일한 함수 서명을 여전히 받아들입니다. func 매개 변수가 발생할 때 do try 블록 만 사용하면되는 편리한 방법이지만 함수의 다른 코드는 오류를 발생시키지 않습니다.


답변