Swift switch 语句的范围错误
Swift range bug with switch-statement
大家好,我是新来的,现在我正在通过编写一些奇特的算法来学习 Swift,这是我在阅读 Apples Swift 书时想到的。
我试图压缩(自动向下转换)任何 IntegerType 值。
这是我的代码的一小段,除了一种情况外几乎可以正常工作:
switch signedValue
{
case Int64(Int8.min)...Int64(Int8.max): compressedValue = Int8(signedValue)
case (Int64(Int8.max) + 1)...Int64(UInt8.max): compressedValue = UInt8(signedValue)
case Int64(Int16.min)...Int64(Int16.max): compressedValue = Int16(signedValue)
case (Int64(Int16.max) + 1)...Int64(UInt16.max): compressedValue = UInt16(signedValue)
case Int64(Int32.min)...Int64(Int32.max): compressedValue = Int32(signedValue)
case (Int64(Int32.max) + 1)...Int64(UInt32.max): compressedValue = UInt32(signedValue)
case Int64(Int.min)...Int64(Int.max): compressedValue = Int(signedValue) // range bug #1 - workaround '..<'
default: compressedValue = signedValue
}
假设 signedValue 的类型为 Int64,输入值为 = 10_000_000_000。
这将导致运行时错误(在 Playground 中):
Execution was interrupted, reason: EXC_BAD_INSTRUCTION ...
任何人都可以帮助我了解这里到底发生了什么。此问题有一个解决方法。我可以使用 '..<' 而不是 '...' 但这不是范围应该如何。
与间隔(有两种风格,半开或封闭)不同,Range
只是半开。因此,当您编写 1...5
时,...
函数会递增右侧参数以创建半开范围 1..<6
.
这样做的结果是您不能拥有跨越整数类型整个长度的范围,因为 1...Int.max
将导致尝试递增 Int.max
,并出现溢出错误. let s = "hello"; let r = s.startIndex...s.endIndex
会出现类似的错误
然而,一切都没有丢失,因为无论如何你都不应该使用范围,这是 ClosedInterval
的工作。由于 ...
运算符用于两者,并且默认为范围(出于重载优先级原因),您需要明确标识类型:
let i64interval: ClosedInterval = Int64(Int64.min)...Int64(Int64.max)
switch signedValue {
// etc
case i64interval: compressedValue = Int(signedValue)
default: compressedValue = signedValue
}
在 the documentation 中查看 Range
类型。它包含以下我以前从未注意到的小信息:
if T has a maximal value, it can serve as an endIndex, but can never be contained in a Range.
T
,在那个引用中,是 Range
中值的类型。因此,如果您有 Int
个 Range
,则 Int
的最大值不能包含在 Range
.
中
这就是为什么如果你把 ..<
放在那里,而不是 ...
。
好问题,顺便说一句...
大家好,我是新来的,现在我正在通过编写一些奇特的算法来学习 Swift,这是我在阅读 Apples Swift 书时想到的。
我试图压缩(自动向下转换)任何 IntegerType 值。 这是我的代码的一小段,除了一种情况外几乎可以正常工作:
switch signedValue
{
case Int64(Int8.min)...Int64(Int8.max): compressedValue = Int8(signedValue)
case (Int64(Int8.max) + 1)...Int64(UInt8.max): compressedValue = UInt8(signedValue)
case Int64(Int16.min)...Int64(Int16.max): compressedValue = Int16(signedValue)
case (Int64(Int16.max) + 1)...Int64(UInt16.max): compressedValue = UInt16(signedValue)
case Int64(Int32.min)...Int64(Int32.max): compressedValue = Int32(signedValue)
case (Int64(Int32.max) + 1)...Int64(UInt32.max): compressedValue = UInt32(signedValue)
case Int64(Int.min)...Int64(Int.max): compressedValue = Int(signedValue) // range bug #1 - workaround '..<'
default: compressedValue = signedValue
}
假设 signedValue 的类型为 Int64,输入值为 = 10_000_000_000。 这将导致运行时错误(在 Playground 中):
Execution was interrupted, reason: EXC_BAD_INSTRUCTION ...
任何人都可以帮助我了解这里到底发生了什么。此问题有一个解决方法。我可以使用 '..<' 而不是 '...' 但这不是范围应该如何。
与间隔(有两种风格,半开或封闭)不同,Range
只是半开。因此,当您编写 1...5
时,...
函数会递增右侧参数以创建半开范围 1..<6
.
这样做的结果是您不能拥有跨越整数类型整个长度的范围,因为 1...Int.max
将导致尝试递增 Int.max
,并出现溢出错误. let s = "hello"; let r = s.startIndex...s.endIndex
然而,一切都没有丢失,因为无论如何你都不应该使用范围,这是 ClosedInterval
的工作。由于 ...
运算符用于两者,并且默认为范围(出于重载优先级原因),您需要明确标识类型:
let i64interval: ClosedInterval = Int64(Int64.min)...Int64(Int64.max)
switch signedValue {
// etc
case i64interval: compressedValue = Int(signedValue)
default: compressedValue = signedValue
}
在 the documentation 中查看 Range
类型。它包含以下我以前从未注意到的小信息:
if T has a maximal value, it can serve as an endIndex, but can never be contained in a Range.
T
,在那个引用中,是 Range
中值的类型。因此,如果您有 Int
个 Range
,则 Int
的最大值不能包含在 Range
.
这就是为什么如果你把 ..<
放在那里,而不是 ...
。
好问题,顺便说一句...