안녕하세요.
Collection에서 flatMap은 많이 사용해봤는데... Optional에서도 map, flatMap을 사용할 수 있더라구요...? (저는 최근에 알았...)
그래서 이번에 Optional에서의 map, flatMap에 대해 알아볼게요.
## map
Optional에서의 map 함수는 Array나 Dictionary에서 사용하는 map 함수랑 약간 달라요.
공식 문서를 보면,
즉, 값이 nil일 경우 nil이 리턴되고, nil이 아닐 경우 클로저로 언래핑된 값을 전달해줘요.
(map을 직접 써보면 파라미터에 언래핑된 값이 전달되는 것을 알 수 있습니다.)
그럼 map을 언제 사용하냐??
Use the map method with a closure that returns a non-optional value.
클로저에서 non-optional 값을 리턴할 때 map을 사용합니다.
아래 코드를 볼까요??
let optionalInt: Int? = 10
let result = optionalInt.map { $0 + 1 }
print(result) // Optional(11)
클로저에서 non-optional을 리턴 하지만 그 결과값은 optional 인 것을 알 수 있습니다.
그럼 클로저에서 optional 값을 리턴하는 것은 안될까요??
되긴 합니다. 되긴 합니다만..
예를 들어서 보여드릴게요.
let optionalInt: Int? = 10
let result1 = optionalInt.map { $0 + 1 }
let result2 = optionalInt.map { Optional($0 + 1) }
print(result1) // Optional(11)
print(result2) // Optional(Optional(11))
클로저에서 명시적으로 optional을 리턴하도록 했을 때..
result2의 타입은 ?? (Optional-Optional) 타입이 되기 때문에 non-optional을 리턴하는 경우에만 사용하라는 것이에요.
아하!!
즉, map을 사용하면 클로저의 리턴값을 명시적으로 Optional로 한번 더 감싸주는 것 같네요!!
이번엔 flatMap에 대해 살펴볼까요?
## flatMap
flatMap도 map과 동일하게 클로저로 넘어오는 파라미터는 언래핑되어서 전달되는 것이 보장됩니다.
Discussion을 살펴보면 map 하고 다른 부분이 있는데요.
Use the flatMap method with a closure that returns an optional value.
map과는 다르게 클로저에서 optional을 리턴할 때 flatMap을 사용하라고 합니다.
위에서 사용한 예시를 그대로 flatMap으로만 바꾸고 결과값을 한번 볼게요.
let optionalInt: Int? = 10
let result1 = optionalInt.flatMap { $0 + 1 }
let result2 = optionalInt.flatMap { Optional($0 + 1) }
print(result1) // Optional(11)
print(result2) // Optional(11)
오홓...
클로저에서 optional을 리턴해도 flatMap의 결과값은 그냥 Optional 이군요.
그럼... flatMap은 어떤 규칙으로 리턴 값 & 타입이 결정되는 것일까요?
제가 flatMap의 구현부를 볼 수 없으니... 여러가지 테스트를 해봤어요.
let optionalInt: Int? = 10
let result1 = optionalInt.flatMap { Optional(Optional($0 + 1)) } // Optional(Optional(11))
let result2 = optionalInt.flatMap { [$0] } // Optional([10])
let result3 = optionalInt.flatMap { [Optional($0)] } // Optional([Optional(10)])
let result4 = optionalInt.flatMap { Optional([$0]) } // Optional([10])
let result5 = optionalInt.flatMap { Optional([Optional($0)]) } // Optional([Optional(10)])
여기서 나온 결론은,
flatMap을 사용하면 클로저의 리턴값을 언래핑한 후에 그걸 다시 Optional로 래핑해주는 것 아닐까 싶어요.
(혹시 더 자세하게 아시는 분 계시면 알려주세요ㅠㅠ)
## 참고
- https://developer.apple.com/documentation/swift/optional
- https://developer.apple.com/documentation/swift/optional/map(_:)-7txtz
- https://developer.apple.com/documentation/swift/optional/flatmap(_:)
이번 글은 여기서 마무리.
'Swift' 카테고리의 다른 글
mutating (1) | 2022.12.18 |
---|---|
@autoclosure (2) | 2022.12.15 |
@inlinable, @usableFromInline (0) | 2022.08.15 |
[Swift 5.7] if let shorthand (0) | 2022.07.05 |
inout (0) | 2022.06.05 |