有人可以向我解释为什么本例中的最后一个案例是编译错误吗?
class A{}
class B: A{}
protocol Finder{
func find< T: A>(_ f: (T)->Bool) -> T?
}
class FinderImpl : Finder{
func find<T : A>(_ f: (T) -> Bool) -> T? {
//In the real code I use T to find the instance. I.e. CoreData
return nil
}
}
let finder = FinderImpl()
//OK
let optionalB : B? = finder.find{_ in true}
let a : A = finder.find{_ in true}!
let b : B = finder.find{(b: B) in true}!
//Compile Error
let b2 : B = finder.find{_ in true}!
让a。编译器使用(A) -> Bool.
作为闭包类型。然后返回类型是A.
让b。这会编译,因为闭包有明确的信息:(B)->Bool
让optionalB。我想知道为什么这个案例有效,这里闭包也没有任何信息。区别在于! operator
错误:在最后一种情况下,编译器无法推断传递给func find的闭包类型。它建议我转换as! B
,因为它认为闭包类型是(A)->Bool
。它没有使用b2 B的参考类型。
重要提示:我无法转换as! B
,因为我需要find函数来实际使用类型B.如果我转换as! B
,该函数将使用类型A并获取错误的实例。代码会编译但结果会出错。
如果我删除了T:A
限制,则没有编译错误。
这对我来说看起来像编译错误。我认为编译器应该使用b2的类型来知道闭包是(B)->Bool
然后是结果类型的find。封闭中的T:A
限制和缺少类型信息导致它失败。
我在这里遗漏了什么吗?有什么想法吗?
答案 0 :(得分:0)
因为Swift无法在最后一个例子中推断出返回类型。
在您的通用函数中,您声明T
必须是A
或A
的子类:
func find<T : A>(_ f: (T) -> Bool) -> T? {
return nil
}
当你在闭包中指定类型时,Swift可以推断出T
实际上是什么。这就是为什么这样做的原因:
finder.find{(b: B) in true}!
^ now T == B
在这里,您没有提供任何类型信息,因此编译器所依赖的唯一内容是泛型函数的声明,即T : A
:
finder.find{ _ in true}! // this return A
^ what type is this? The compiler doesn't have any extra
information so it must be A according to the declaration
您可以通过进行显式转换来获取编译器:
let b2 : B = finder.find{ _ in true}! as! B
或提供类型信息:
let b3 : B = finder.find{ (_: B) in true}!
(这是为了让它只能编译。代码显然会在运行时崩溃,因为你强制解包一个零值)