我今天又玩了 Swift,需要一个undefined()
函数。基本上是一个函数,可以是您想要的任何类型,但在实际运行/评估时会崩溃。如果您还没有时间实现某个表达式但想查看程序类型是否检查,这将非常有用。
我还实现了一个Result<T>
和一个(有问题的)函数,如果不成功则chain
返回 left ,否则返回 right 。因此,签名是。我将右边定义为因为如果左边是失败的,则不需要评估它。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>
(而不是() -> 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)