我想知道是否有办法指定一个约束为Range或ClosedRange值的数字类型。
非编译示例:
typealias QuarterNumber = 1...4
typealias VolumeLevel = 0...11
typealias ObtuseAngle = 90.0<..<180.0
现在,对于第一个例子,我可能会创建类似的东西:
enum QuarterNumber : Int {
case First = 1
case Second = 2
case Third = 3
case Fourth = 4
}
然而,在VolumeLevel
我绝对想要使用原始数字的情况下,这变得笨拙。在ObtuseAngle
情况下,指定它可能需要的所有单个值是完全不切实际的。
答案 0 :(得分:2)
我可能采用的一种方法是使用包装类型:
struct ObtuseAngle {
var value: Double
}
extension ObtuseAngle : ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral {
init(floatLiteral v: FloatLiteralType) {
guard 90.0 < v && v < 180.0 else {
preconditionFailure("Invalid angle")
}
self.init(value: v)
}
init(integerLiteral v: IntegerLiteralType) {
self.init(floatLiteral: Double(v))
}
}
let x: ObtuseAngle = 115 // works
let y: ObtuseAngle = 45 // runtime crash
缺点是现在实际值隐藏在.value
中,而不是更“原始”的类型。我也失去了我在“基础”类型上所有的数学运算符,但这有点意义,因为例如添加时,两个钝角可能不是钝角,并且将它们相乘不会真正产生角度类型等。
请注意,在此示例中,使用类型Measurement<UnitAngle>
声明值并将其初始化为Measurement(value: v, unit: UnitAngle.degrees)
也可能是合适的。