我今天再次使用Swift,需要undefined()
功能。基本上是一个函数,可以是您想要的任何类型,但在实际运行/评估时崩溃。如果您还没有时间实现某个表达式,但希望查看程序类型是否有效,那么这很有用。
我还实施了一个Result<T>
和一个(可疑的)函数chain
,如果不成功则返回左Result<>
,否则返回右Result<>
。因此,签名为chain<L,R>(l : Result<L>, r : @autoclosure () -> Result<R>) -> Result<R>
。我将权限Result<>
定义为@autoclosure
,因为如果左边是失败,则无需对其进行评估。
我对这些内容的有用性(或改进)不感兴趣,我只是对我的程序在标记为[L3]
的行中崩溃感兴趣。
请注意
[L1]
正常工作(||
是懒惰评估的)[L2]
工作正常(chain
在其正确的论证中也很懒惰)但是,奇怪的是
[L3]
崩溃评估undefined()
根据我的理解,L2和L3在运行时应该是等价的:L3只是告诉类型检查器它已经知道的东西......如果你将undefined
的类型更改为{{() -> Result<T>
,那么同样的效果会发生1}}(而不是() -> T
),即使没有as Result<String>
,它也能正常工作。
这是我的全部代码:
import Foundation
enum Result<T> {
case Success(@autoclosure () -> T);
case Failure(@autoclosure () -> NSError)
}
func undefined<T>(file:StaticString=__FILE__, line:UWord=__LINE__) -> T {
fatalError("undefined", file:file, line:line)
}
func chain<L,R>(l : Result<L>, r : @autoclosure () -> Result<R>) -> Result<R> {
switch(l) {
case .Failure(let f):
return .Failure(f())
case .Success(let _):
return r()
}
}
func testEvaluation() {
let error = NSError(domain: NSPOSIXErrorDomain, code: Int(ENOENT), userInfo: nil)
let failure : Result<String> = .Failure(error)
assert(true || undefined() as Bool) // [L1]: works
let x : Result<String> = chain(failure, undefined() as Result<String>) // [L2]: works
print("x = \(x)\n")
let y : Result<String> = chain(failure, undefined()) // [L3]: CRASHES THE PROGRAM EVALUATING undefined()
print("y = \(y)\n")
}
testEvaluation()
信不信由你,程序的输出是:
x = (Enum Value)
fatal error: undefined: file main.swift, line 27
Illegal instruction: 4
那不对!为什么as Result<String>
(这是L2和L3之间的唯一区别)会改变程序的输出?这应该在类型检查器中完全处理,这意味着在编译时,不是吗?编译错误?
重现这一点的最快方法应该是:
cd /tmp
pbpaste > main.swift
xcrun -sdk macosx swiftc main.swift
./main
实际输出:
x = (Enum Value)
fatal error: undefined: file main.swift, line 27
Illegal instruction: 4
预期产出:
x = (Enum Value)
y = (Enum Value)