这个小通用函数会产生一个有趣的运行时错误:
func clamps <T: Comparable> (from: T, to: T)(_ x: T) -> T {
if x < from { return from }
if x > to { return to }
return x
}
(正如我在下面解释的那样,请记住,我无法进一步显着减少错误生成代码 - 除非删除其中一条if
行!)
我们可以使用它来生成clamp
函数,如下所示:
let clamp: Int -> Int = clamps(2, 4)
我们会打印一些这样的例子:
for i in 0...5 {
println("clamp(\(i)) -> \(clamp(i))")
}
在Debug中运行时,for循环产生以下输出:
// clamp(0) -> 2
// clamp(1) -> 2
// clamp(2) -> 2
// clamp(3) -> 3
// clamp(4) -> 4
// clamp(5) -> 4
这是我们所期望的。但是,在Release配置中运行时,我们得到:
// clamp(0) -> 4296676200
// clamp(1) -> 4296676200
// clamp(2) -> 4296676200
// clamp(3) -> 4296676200
// clamp(4) -> 4296676200
// clamp(5) -> 4296676200
请注意,这个数字非常接近UInt32.max
(即4294967295),所以我的猜测是它是某种UnicodeScalar值...如果你将clamps
与其他类型一起使用,与CGFloat
一样,结果也同样荒谬。
如果我们重写函数以避免Swift的currying语法,那么Debug和Release中的一切都可以正常工作:
func clamps2 <T: Comparable> (from: T, to: T) -> T -> T {
return {
if $0 < from { return from }
if $0 > to { return to }
return $0
}
}
let clamp2: Int -> Int = clamps2(2, 4)
for i in 0...5 {
println("clamp2(\(i)) -> \(clamp2(i))")
}
// clamp2(0) -> 2
// clamp2(1) -> 2
// clamp2(2) -> 2
// clamp2(3) -> 3
// clamp2(4) -> 4
// clamp2(5) -> 4
所以问题是这是真的是一个错误,还是我错过了对整个世界显而易见的事情?
作为最后一个例子,考虑这个(一个无用的函数)不会重现错误:
func f <T: Comparable> (from: T, to: T)(_ x: T) -> T {
if x < from {
return x // <---- returning x
}
return x
}
但这样做:
func f <T: Comparable> (from: T, to: T)(_ x: T) -> T {
if x < from {
return from // <---- returning from
}
return x
}
我的错误报告刚收到Apple Developer Relations发来的消息称他们认为此问题已在最新的Xcode 7测试版中得到解决。