안녕하세요~! 오늘은 새롭게 소개된 Result Type을 소개해 드리려고합니다.
Result Type은 아래 코드 처럼 enum으로 선언 되어있고
성공과, 실패를 Generic으로 받고 있습니다. 실패는 무조건 에러 타입이구요
@frozen enum Result<Success, Failure> where Failure : Error
기존의 에러처리 방식을 개선하고 결과값을 명확히 받기 위해
Result Type이 나왔다고 보여지는데요.
왜 그런지 아래 예제를 통해 함께 보시죠~!
아래 주문을 받는 받았을 때 발생 할 수 있는 간단한 에러를 정의 했습니다.
enum OrderError: Error {
case LackOfMoney
}
메뉴는 햄버거가 좋을거 같아요.
햄버거 종류와 종류에 따른 가격을 받을 수 있습니다.
enum HamburgerMenu {
case cheezeBurger, bigMac, spicyCrispy
var price: Int {
switch self {
case .cheezeBurger:
return 6_000
case .bigMac:
return 5_000
case .spicyCrispy:
return 5_500
}
}
}
주문하는 고객님도 있어야 할거 같아요.
갖고 있는돈과 메뉴를 받아서 주문하는 행위도 추가 했습니다.
돈이 모자르다면 에러를 주고 있어요.
struct Customer {
var money: Int
func order(hamburgerMenu menu: HamburgerMenu) throws -> Bool {
if money < menu.price {
throw OrderError.LackOfMoney
}
return true
}
}
고객 한 분이 들어오고 주문을 합니다.
let customer = Customer(money: 2_000)
do {
try customer.order(hamburgerMenu: .cheezeBurger)
} catch {
print(error)
}
위 코드를 보면서 에러 처리시 보이는 문제점들이 몇 가지 있습니다.
- 고객이 주문할때 에러 발생시 throws로 에러를 던지는데, 이때 에러의 형식을 정할 수 없습니다. (에러 타입에 대한 명확성x)
- 저희가 정의한 에러타입이 아닌 에러 프로토콜을 주고 있어 어떤 에러 타입인지 바로 알 수 없습니다. (do - catch문 안에서)
- 에러를 받는 입장에서는 어떤 에러인지 확인 후, 타입 캐스팅을 통해 정의한 에러를 사용할 수 있습니다.
- 정의한 에러 타입에서 새로운 타입이 추가되어도 컴파일러는 알 수 없어 런타임시(앱 실행중에) 해당 에러를 처리 안했을때 생기는 문제점들이 있을 수 있습니다.
위에 언급한 문제들이 어떻게 해결되는지
새롭게 발표한 Result Type을 통해서 코드가 어떻게 변경되는지 보시죠~!
사용자가 주문 행위 리턴 값이 Result 타입으로 받고 있습니다.
throws로 던졌을때 처리와 비교 했을때 차이점이 보이고 있습니다.
실패했을때 받는 에러와 성공했을때 받는 결과값이 명확하게 보이고, 어떤 에러타입과 결과값을 받을지 알 수 있습니다.
struct Customer {
var money: Int
func order(hamburgerMenu menu: HamburgerMenu) -> Result<Bool, OrderError> {
if money < menu.price {
return .failure(.LackOfMoney)
}
return .success(true)
}
}
고객이 주문하는 과정에서도
do - catch문으로 처리했을때와 result 타입을 받아 switch문으로 처리 했을때도 차이가 있습니다.
성공과 실패 상황으로 극명하게 나뉜 모습이 더 깔끔하고 명확해진 모습을 볼 수 있습니다.
에러타입에 대해서도 타입 캐스팅도 필요없고, 어떤 에러 타입이 오는지 명확해지죠. 해당 에러에 정의한 타입이 추가되었을때도
컴파일시 해당 타입에 대해 처리되지 않은 부분들을 미리 잡아주기 때문에 코드 안정성도 높아집니다.
let customer = Customer(money: 2000)
let result = customer.order(hamburgerMenu: .cheezeBurger)
switch result {
case .success(let success):
break
case .failure(let error):
break
}
// 성공했을 경우, 결과값만 받아서 처리하고 싶을때
if let sucess = try? result.get() {
}
기존 do - catch + throws을 이용해서 에러 타입을 처리하기 보단 소개해드린 Result Type을 이용해서
해보시는건 어떨까요?.
개인적으로 Result Type으로 정의하지 못한 부분들을 리팩토링 해볼 예정입니다.
오늘은 여기까지 하겠습니다. 감사합니다~!!
함께 읽어보면 좋은 글:
참조:
https://github.com/apple/swift-evolution/blob/main/proposals/0235-add-result.md
'Apple > Apple_Swift' 카테고리의 다른 글
Swift5.0 중첩된 Optionals(??) 평면화 하기 SE-0230 (0) | 2023.01.10 |
---|---|
Swift5.0 향후 변경 될 수 있는 Enum(열거형) switch @unknown 속성 처리 SE-0192 (0) | 2023.01.03 |
Swift5.0 Character Properties (띄어쓰기, 공백, 숫자, 소문자 등등.. 확인 가능해요) SE-0221 (0) | 2022.12.26 |
Swift5.0 Dictionary를 위한 고차함수 .compactMapValues 소개 SE-0218 (2) | 2022.12.23 |
Swift 5.0 유니코드 스칼라 프로퍼티 추가 (Unicode Scalar Properties) SE-0211 (2) | 2022.12.20 |