很抱歉,如果这是一个愚蠢的问题,但我想知道在Swift中是否有办法创建一个专门保存严格大于零的数字的类型,并且在编译时强制执行值的“正面性”。
例如,我可以创建像
这样的代码func divide(x: PositiveNumber, y: PositiveNumber){
return x / y
}
这样
divide(1, 3)
有效但
divide(1, 0)
不会编译?
我能想出的最接近的结果是只有一个易错初始值设定项的结构,这个类型具有正值或为零:
struct PositiveNumber {
let value: Float
init?(value: Float){
if value > 0 {
self.value = value
} else {
return nil
}
}
}
func / (left: PositiveNumber, right: PositiveNumber) -> Float {
return left.value / right.value
}
func divide(x: PositiveNumber?, y: PositiveNumber?) -> Float? {
if let x = x, y = y {
return x / y
}
return nil
}
let x1 = PositiveNumber(value: 1)
let y1 = PositiveNumber(value: 3)
let x2 = PositiveNumber(value: -1)
let y2 = PositiveNumber(value: 0)
divide(x1, y: y1)! // .333
divide(x2, y: y2)! // runtime error
这并不可怕,但我们仍然需要处理很多可选的处理/解包。我问这个问题,因为我的代码中有很多地方需要检查一个值是不是零,我很好奇是否有办法删除该代码并让编译器处理它。基于结构的解决方案需要几乎相同数量的代码。
答案 0 :(得分:1)
这个要点包含一个符合Float符合的几乎所有内容的结构。它只是Float的一个香草副本,可以根据自己的喜好进行更改。
您是否考虑过自定义运营商?
infix operator /+ { associativity left precedence 150 }
func /+(lhs:Float,rhs:Float) -> Float? {
guard rhs > 0 else {
return nil
}
return lhs / rhs
}
let test = 2 /+ -1 // nil
let test2 = 2 /+ 1 // 2
let test3 = 2 /+ 1 + 2 // warning
如果让它返回可选项或枚举值或不同的协议,那并不重要。你将不得不处理回报。但是这样你就会得到编译器警告。
有限数字类型只有一个操作员来处理分部:
您可以完全改变数学并创建一个PositiveNumber类型,在除以小于零的值时返回NaN。
public struct PositiveFloat {
public var value: Float
/// Create an instance initialized to zero.
public init() {
self.value = 0
}
/// Create an instance initialized to `value`.
public init(_ value: Float) {
self.value = value
}
public init(_ value: PositiveFloat) {
self.value = value.value
}
}
extension Float {
public var positive : PositiveFloat {
return PositiveFloat(self)
}
}
public func /(lhs:Float,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs / rhs.value
} else {
return Float.NaN
}
}
public func /(lhs:PositiveFloat,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs.value / rhs.value
} else {
return Float.NaN
}
}
let testNormal : Float = 10
let testFloat : Float = -5
let test = testFloat / testNormal.positive
if test.isNaN {
// do stuff
}