flatMap 및 이중 Optional
let arr: [Int?] = [1,3,nil,4]
let arr1: [Int?] = arr.flatMap { $0 } // [{some 1}, {some 3}, nil, {some 4}]
let arr2: [Int?] = arr.flatMap {
next -> Int?? in
next
} // [{some 1}, {some 3}, nil, {some 4}]
let arr3: [Int?] = arr.flatMap {
next -> Int? in
next
} // [{some 1}, {some 3}, {some 4}]
let arr4 = arr.flatMap { $0 } // [1,3,4]
let arr5: [Int] = arr.flatMap { $0 } // [1,3,4]
나는 왜 이 몇 단락의 코드가 flat Map에 다른 행동을 하게 하는지 이해하지 못하고 며칠 동안 끊임없이 생각했지만 아직 결과가 없어서 Stack Over Flow에 가서 이 문제를 제기하기로 결정했다. 문제는 여기에 있다. 다행히도 바로 누군가가 이 문제에 대답했고 대답도 잘했다. 나는 다른 사람의 답안과 자신의 이해를 기록했다.
많은 사람들이 Array의 flatMap command+click에 대해 flatMap의 성명을 들여다볼 때 Sequence Type 아래에 두 개가 있다는 것을 발견할 수 있을 거라고 믿습니다.
public func flatMap(transform: (Self.Generator.Element) throws -> S) rethrows -> [S.Generator.Element]
public func flatMap(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
첫 번째는 그룹을 평평하게 찍는 데 쓰이고 두 번째는nil값을 제거하는 데 쓰인다. 여기는 이 문제에 대한 부분적인 해석이 있지만 아직 상세하지 않다. 그래서 나는 Swift의 원본 코드에서 찾았고 마침내 flatMap의 실현을 찾았다. 여기에 부분적인 코드를 붙였다.
public func flatMap(
_ transform: (Elements.Iterator.Element) -> SegmentOfResult
) -> LazySequence<
FlattenSequence>> {
return self.map(transform).flatten()
}
public func flatMap(
_ transform: (Elements.Iterator.Element) -> ElementOfResult?
) -> LazyMapSequence<
LazyFilterSequence<
LazyMapSequence>,
ElementOfResult
> {
return self.map(transform).filter { $0 != nil }.map { $0! }
}
첫 번째 flatMap은 먼저 자신에게 맵 조작을 한 다음에 자신에게 flatten 조작을 한다.
두 번째 flatMap은 비교적 재미있다. 먼저 자신에게 맵 조작을 한 다음에 nil 값을 필터하고 마지막에 optional을 일반 값으로 전환한다.
분명히 우리가 여기서 토론하고자 하는 것은 두 번째 플래트맵이다.
flatMap의 반환값에 대해 어떠한 제한도 하지 않을 때 위의 코드에 있는arr4에 대응합니다. 이때 T는 인트로 추정되기 때문에tansform 클립을 간소화한 형식은
Int? -> Int?
입니다. 이 클립은 맵에 전달되는 것이므로 주의하십시오.Array 맵의 설명을 보십시오.
public func map(@noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
맵의 원리를 생각해 보면 매우 간단하다. 사실은 전체 수조를 두루 훑어보고 모든 원소에transform 함수를 실행한 다음에 이 원소를 포함하는 새로운 수조를 되돌려주는 것이다.우리가 전송한transform 클립에 대해 이 맵은 아무것도 하지 않은 것과 같기 때문에 다음 Filter 작업에 사용할 수 있는 그룹입니까? 아니면 [Int?]입니까?다음은 순서대로 나일값을 제거하고 비optional값으로 비추는 것입니다.
arr5에 대해서 말하자면, 상황은 같다.
flatMap의 반환 값이 [Int?]임을 나타낼 때상황이 달라졌다.T가 Int?으로 추정됩니다.트랜스포머 클립을 간소화한 후의 유형은
Int? -> Int??
로,arr1과arr2는 분명히 등가이다. 우리가 먼저 분석을 해 보자. 먼저 그룹을 옮겨다니며 그룹의 요소에 대해transform 조작을 한다. 트랜스포머 클립이 되돌아오는 유형은 Int???그래서 이 때 되돌아오는 새 그룹의 원소의 유형은 Int??
이거나 더 정확히 Optional>
이다. 다음에 그룹에 nil값을 제거한다. 왜냐하면 이 그룹에 nil이 없기 때문이다(이전의 nil은 맵에 의해 Optional
). 그래서 Filter는 작용하지 않았고 마지막으로 맵은 원소를 강제로 해제한다Optional
.여기까지 일이 끝나지 않았습니다. 제가 가장 이해할 수 없는 것은arr3이라는 상황입니다. arr1과 마찬가지로 반환값은 모두 강제로 [Int?]로 가리키고 있습니다.그러나 변화가 발생한 것은 전송된transform 클립이다. 원래 받아야 할 유형은
Int? -> Int??
인데 전송된transform 클립은 Int? -> Int?
인데 왜 가능한가?내가 앞서 언급한 Stack Over Flow의 대답에서 이 열성적인 @originaluser2는 나에게 이런 대답을 주었다.
Because you explicitly annotate the return type of the closure to be
Int?
, the closure will get implicitly promoted from (Element) -> Int?
to (Element) -> Int??
(closure return types can get freely promoted in the same way as other types) – rather than the element itself being promoted from Int?
to Int??
, as without the type annotation the closure would be inferred to be (Element) -> Int??
번역하면
Int? -> Int?
는 Int? -> Int??
로 승급할 수 있거나 하나의 수용Int? -> Int??
의 함수에 대해서도 수용할 수 있다Int? -> Int?
.그리고 그는 아래의 예를 들었다.
func optionalIntArrayWithElement(closure: () -> Int??) -> [Int?] {
let c = closure() // of type Int??
if let c = c { // of type Int?
return [c]
} else {
return []
}
}
// another quirk: if you don't explicitly define the type of the optional (i.e write 'nil'),
// then nil won't get double wrapped in either circumstance
let elementA : () -> Int? = {Optional.None} // () -> Int?
let elementB : () -> Int?? = {Optional.None} // () -> Int??
// (1) nil gets picked up by the if let, as the closure gets implicitly upcast from () -> Int? to () -> Int??
let arr = optionalIntArrayWithElement(elementA)
// (2) nil doesn't get picked up by the if let as the element itself gets promoted to a double wrapped optional
let arr2 = optionalIntArrayWithElement(elementB)
if arr.isEmpty {
print("nil was filtered out of arr") // this prints
}
if arr2.isEmpty {
print("nil was filtered out of arr2") // this doesn't print
}
우리는
optionalIntArrayWithElement
에 필요한 것은 하나() -> Int??
의 클로즈업이고 elementA
는 하나() -> Int?
이지만 전달에 전혀 문제가 없다는 것을 알 수 있다.그런 다음 코드에 대한 설명을 봅니다.
another quirk: if you don't explicitly define the type of the optional (i.e write 'nil'), then nil won't get double wrapped in either circumstance
즉, 단순히 닐에게 부여된 변수
Int??
만 있다면 이 닐은 이중optionla에 감싸이지 않는다. 이중optional에 대해서는 야옹신 편을 볼 수 있다.이때 가장 어려운 부분이 왔습니다. 다음은 제 이해입니다. 완전히 정확한지 여러분께 토론할 수 있도록 하겠습니다.
처음부터 말하자면, 우선 우리는 arr를 [Int?]라고 성명한다.안의nil값에 대해 이때와
optional.None
등가, 우리map arr일 때, 즉 안의원소를transform 조작할 때 이때의transform 함수는 되돌아오기Int??
로 높아졌지만 원소의nil값은 보통nil이기 때문에 이때nil는Optional>.None
로 변하지 않았고 일반적인 비nil은 당연히 Optional>.Some(3)
등으로 변화할 수 있다.그래서 마지막에nil값은 제거되었지만 다른 비nil값은 여전히 변하지 않았다.그러나 여기에 또 다른 문제가 있다. 바로transform이 기본적으로
Int??
형식으로 되돌아갈 때, nil 값이 이중 nil로 비추는 것이 분명하다. 왜 그런가?묵인하는 행동인가?누군가 해답을 분석할 수 있기를 기대한다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.