通用参数';T';无法在赋值后推断 //Xcode 11.6/Swift 5 进口基金会 func f(u:(T)->Void){} @可丢弃结果 func g(u:Int)->Int{0} f{g($0)}//编译罚款 f{let}=g($0)}//无法推断泛型参数“T”

通用参数';T';无法在赋值后推断 //Xcode 11.6/Swift 5 进口基金会 func f(u:(T)->Void){} @可丢弃结果 func g(u:Int)->Int{0} f{g($0)}//编译罚款 f{let}=g($0)}//无法推断泛型参数“T”,swift,generics,Swift,Generics,在上面的代码中,泛型函数f需要一个接受类型为T的参数的函数作为其参数 函数g采用Int类型的参数 当我写f{g($0)}时,代码会编译。我相信(如果我错了,请纠正我),这是因为编译器可以根据g的参数类型推断T是Int 但是,当我尝试使用返回值g执行某些操作时,例如在let=g($0)行中,编译器抱怨它无法再推断T的类型 在我看来,g的返回类型应该与编译器如何推断T的类型无关,但显然它确实如此 有人能解释一下为什么会发生这种情况,以及可以做些什么(如果有的话)来纠正它吗?看起来@discardab

在上面的代码中,泛型函数
f
需要一个接受类型为
T
的参数的函数作为其参数

函数
g
采用
Int
类型的参数

当我写
f{g($0)}
时,代码会编译。我相信(如果我错了,请纠正我),这是因为编译器可以根据
g
的参数类型推断
T
Int

但是,当我尝试使用返回值
g
执行某些操作时,例如在
let=g($0)
行中,编译器抱怨它无法再推断
T
的类型

在我看来,
g
的返回类型应该与编译器如何推断
T
的类型无关,但显然它确实如此


有人能解释一下为什么会发生这种情况,以及可以做些什么(如果有的话)来纠正它吗?

看起来@discardableResult让您能够拥有两种类型的函数:

g(:Int)->Intg(:Int)->Void(当您不想使用函数的结果时)

我认为

f{g($0)}
-这里您的f可以推断类型,因为它具有相同的类型

// 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{let}=g($0)}
-在这种情况下,g函数的类型不同于f函数

(_: (T) -> Void) and (_: (Int) -> Void)
如果删除“let”,它将再次编译:

(_: (T) -> Void) and (_: (Int) -> Int)
我认为
f{let}=g($0)}
-仅返回Int值
f{{{ug=g($0)}
-返回函数({:(Int)->Int)


可能是这里的一个键

函数f接受一个函数作为参数,而该函数又接受类型为
T
的参数,并且不返回任何内容(
Void
)。对于自动推断类型的闭包,它必须由单个(有时是简单的)表达式组成。任何复杂的事情都会使编译器难以推断(从编译器的角度来看,这是有意义的)。显然,就编译器而言,
let=g($0)
是一个复杂的语句。有关更多信息,请参阅此

这可能是编译器错误,也可能不是

众所周知,Swift不会试图推断某些闭包的类型,即多语句闭包:

这是正确的行为:Swift不会从多语句闭包的主体中推断参数或返回类型

但是,闭包只包含一条语句,具体来说是一条声明。尽管很奇怪,但他们设计它的目的可能是,如果闭包也包含一个声明,Swift就不会试图推断类型。例如,这也不会编译

f { _ = g($0) }
如果这是出于设计,那么它背后的基本原理可能是因为闭包中的单个声明没有多大意义。无论声明什么,都不会被使用

但同样,这只是猜测,这也可能是一个bug

要解决此问题,只需将其作为非a声明:

f { let x: Int = $0 } // nothing to do with "g"! The issue seems to be with declarations


f{let{ug=g($0)}
中,你认为T是什么,为什么?@matt我认为
T
Int
(或者应该是),因为
g
明确地接受
Int
。谢谢你链接到SR-1570。现在看来很明显,这是一个预期的行为,而这只是一个缺陷,因为它很难在编译器中实现。显式指定传递给
f
的闭包的函数类型修复了问题,例如
f{(\ui:Int)->Void in let{=g(i)}
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