您可能知道,Swift可以根据用途推断出类型.例如,只要编译器能够推断类型,您就可以使重载方法仅在返回类型上有所不同并自由使用它们.例如,借助于附加的显式类型变量,它将保存此类方法的返回值.
我发现了一些有趣的时刻.想象一下这堂课:
class MyClass {
enum MyError: Error {
case notImplemented
case someException
}
func fun1() throws -> Any {
throw MyError.notImplemented
}
func fun1() -> Int {
return 1
}
func fun2() throws -> Any {
throw MyError.notImplemented
}
func fun2() throws -> Int {
if false {
throw MyError.someException
} else {
return 2
}
}
}
Run Code Online (Sandbox Code Playgroud)
当然,它会像:
let myClass = MyClass()
// let resul1 = myClass.fun1() // error: ambiguous use of 'fun1()'
let result1: Int = myClass.fun1() // OK
Run Code Online (Sandbox Code Playgroud)
但接下来你可以写下这样的东西:
// print(myClass.fun1()) // error: call can throw but is not marked with 'try'
// BUT
print(try? myClass.fun1()) // warning: no calls to throwing functions occur within 'try' expression
Run Code Online (Sandbox Code Playgroud)
所以看起来像是互相排斥的陈述.编译器试图选择正确的功能; 第一次调用它试图强制从Int转换为Any,但是它试图用第二个做什么?
而且,代码就像
if let result2 = try? myClass.fun2() { // No warnings
print(result2)
}
Run Code Online (Sandbox Code Playgroud)
将没有警告,所以可以假设编译器能够在这里选择正确的重载(可能基于事实,其中一个重载实际上没有返回任何东西而只抛出).
我最后的假设是对的吗?警告是否fun1()符合逻辑?我们是否有一些技巧来欺骗编译器或帮助它进行类型推断?
显然你永远不应该写这样的代码.它有太多方法可以咬你,正如你所看到的那样.但是,让我们看看为什么.
首先,try它只是Swift中的一种装饰.它不适合编译器.这是给你的.编译器计算出所有类型,然后确定是否有try必要.它不try用于弄清楚类型.你可以在这里看到这个:
class X {
func x() throws -> X {
return self
}
}
let y = try X().x().x()
Run Code Online (Sandbox Code Playgroud)
您只需要try一次,即使链中有多个投掷呼叫.想象一下,如果x()基于throws vs non-throws 创建了重载,这将如何工作.答案是"它没关系",因为编译器并不关心try.
接下来是类型推断与类型强制的问题.这是类型推断:
let resul1 = myClass.fun1() // error: ambiguous use of 'fun1()'
Run Code Online (Sandbox Code Playgroud)
斯威夫特永远不会推断出一种模棱两可的类型.这可能是Any or it could beInt`,所以它放弃了.
这不是类型推断(类型已知):
let result1: Int = myClass.fun1() // OK
Run Code Online (Sandbox Code Playgroud)
这也有一个已知的,明确的类型(注意没有?):
let x : Any = try myClass.fun1()
Run Code Online (Sandbox Code Playgroud)
但这需要类型强制(很像你的打印示例)
let x : Any = try? myClass.fun1() // Expression implicitly coerced from `Int?` to `Any`
// No calls to throwing function occur within 'try' expression
Run Code Online (Sandbox Code Playgroud)
为什么要调用这个Int版本?try?返回一个Optional(可以是Any).所以Swift在这里有一个选项,可以返回Int?并强制转换为Any或Any?强制转换为Any.Swift几乎总是喜欢真正的类型Any(并且它非常讨厌Any?).这是Any您的代码中要避免的众多原因之一.它以奇怪的方式与Optional交互.可以说这应该是一个错误,但是Any这种类型的松鼠类型很难确定其所有的角落情况.
那么这如何适用print?参数print是Any,所以这就像let x: Any =...示例而不是像let x =...示例.
在考虑这些事情时要记住一些自动强制:
那么混合抛出/非投掷与Any/Any的转换?转换,try?投入混合(将所有内容推广到可选项),你创造了一个完美的混乱风暴.
显然你永远不应该写这样的代码.