할당 후 일반 매개 변수 'T'를 유추 할 수 없습니다.
// Xcode 11.6 / Swift 5
import Foundation
func f<T>(_: (T) -> Void) { }
@discardableResult
func g(_: Int) -> Int { 0 }
f { g($0) } // compiles fine f { let _ = g($0) } // Generic parameter 'T' could not be inferred
위의 코드에서 제네릭 함수 f
는 유형의 인수를 취하는 함수를 인수로 예상합니다 T
.
이 함수 g
는 유형의 인수를 사용합니다 Int
.
를 작성할 때 f { g($0) }
코드가 컴파일됩니다. 내가 생각 컴파일러가 추론 할 수 있기 때문에 (내가 틀렸다면 수정하시기 바랍니다)이 컴파일 T
입니다 Int
기반 g
의 인수 유형.
그러나 g
예를 들어 let _ = g($0)
줄 에서 반환 값으로 무언가를 시도 하면 컴파일러는 더 이상 유형을 추론 할 수 없다고 불평합니다 T
.
의 반환 유형은 g
컴파일러가 T
의 유형을 추론하는 방법과 관련이 없어야 하지만 분명히 그렇습니다 .
왜 이런 일이 발생하는지, 그리고 그것을 시정하기 위해 무엇을 할 수 있는지에 대해 밝힐 수 있습니까?
답변
이것은 컴파일러 버그 일 수도 있고 아닐 수도 있습니다.
Swift는 SR-1570에서 말한 것처럼 일부 클로저의 유형, 즉 다중 문 유형을 추론하지 않는 것으로 알려져 있습니다 .
이것은 올바른 동작입니다. Swift는 다중 문 클로저의 본문에서 매개 변수를 유추하거나 유형을 반환하지 않습니다.
그러나 클로저는 하나의 선언문으로 구성되며 하나의 선언은 구체적입니다. 이상 하긴하지만 클로저가 하나의 선언 도 포함하는 경우 Swift가 유형을 추론하지 않도록 설계했을 수 있습니다. 예를 들어 이것은 컴파일되지 않습니다.
f { let x: Int = $0 } // nothing to do with "g"! The issue seems to be with declarations
이것이 의도적으로 설계된 경우 그 이유는 클로저의 단일 선언이 어쨌든 의미가 없기 때문일 수 있습니다. 선언 된 내용은 사용되지 않습니다.
그러나 이것은 단지 추측 일 뿐이며 버그가 될 수도 있습니다.
이를 고치려면 단순히 선언이 아닌 것으로 만드십시오.
f { _ = g($0) } // this, without the "let", is IMO the idiomatic way to ignore the function result
또는
f { g($0) } // g has @discardableResult anyway, so you don't even need the wildcard
이 함수 f
는 함수를 매개 변수로 취하며,이 매개 변수는 유형의 매개 변수를 취하고 T
아무것도 반환하지 않습니다 ( Void
). 클로저가 유형을 자동으로 추론하려면 단일 (때로는 단순한) 표현식으로 구성되어야합니다. 복잡한 것은 컴파일러가 추론하기 어렵게 만듭니다 (컴파일러의 관점에서 볼 때 의미가 있음). 분명히 let _ = g($0)
컴파일러에 관한 한 복잡한 문장입니다. 자세한 내용은이 메일 링리스트 토론을 참조하십시오.
@discardableResult가 두 가지 유형의 기능을 제공하는 것처럼 보입니다.
g (_ : Int)-> Int and g (_ : Int)-> Void (함수의 결과를 사용하고 싶지 않을 때)
내 생각에는
f { g($0) }
-여기서 f 는 동일한 유형을 가지고 있기 때문에 유형을 추론 할 수 있습니다.
(_: (T) -> Void) and (_: (Int) -> Void)
f { let _ = g($0) }
-이 경우 g 함수의 유형이 f 함수와 다릅니다.
(_: (T) -> Void) and (_: (Int) -> Int)
"let"을 제거하면 다시 컴파일됩니다.
f { _ = g($0) }
나는 생각한다 f { let _ = g($0) }
-Int 값 만 반환 f { _ = g($0) }
-함수 반환 (_ : (Int)-> Int)
여기 열쇠일지도 몰라