扩展FixedWidthInteger
和创建一个实例泛型方法来接受RangeExpression
并处理边缘情况:
extension FixedWidthInteger {
func clamped<R: RangeExpression>(with range: R) -> Self where R.Bound == Self {
switch range {
case let range as ClosedRange<Self>:
return Swift.min(range.upperBound, Swift.max(range.lowerBound, self))
case let range as PartialRangeFrom<Self>:
return Swift.max(range.lowerBound, self)
case let range as PartialRangeThrough<Self>:
return Swift.min(range.upperBound, self)
case let range as Range<Self>:
return Swift.min(range.dropLast().upperBound, Swift.max(range.lowerBound, self))
case let range as PartialRangeUpTo<Self>:
return Swift.min(range.upperBound.advanced(by: -1), self)
default: return self
}
}
}
游乐场测试:
100.clamped(with: 1...) // 100
100.clamped(with: ..<100) // 99
100.clamped(with: ...100) // 100
100.clamped(with: 1..<100) // 99
100.clamped(with: 1...100) // 100
0.clamped(with: 1...) // 1
0.clamped(with: ..<100) // 0
0.clamped(with: ...100) // 0
0.clamped(with: 1..<100) // 1
0.clamped(with: 1...100) // 1
要使用 FloatingPoint 实现获得相同的结果,您可以将其 nextDown 属性用于边缘情况:
extension BinaryFloatingPoint {
func clamped<R: RangeExpression>(with range: R) -> Self where R.Bound == Self {
switch range {
case let range as ClosedRange<Self>:
return Swift.min(range.upperBound, Swift.max(range.lowerBound, self))
case let range as PartialRangeFrom<Self>:
return Swift.max(range.lowerBound, self)
case let range as PartialRangeThrough<Self>:
return Swift.min(range.upperBound, self)
case let range as Range<Self>:
return Swift.min(range.upperBound.nextDown, Swift.max(range.lowerBound, self))
case let range as PartialRangeUpTo<Self>:
return Swift.min(range.upperBound.nextDown, self)
default: return self
}
}
}
游乐场测试:
let value = 100.0
value.clamped(with: 1...) // 100
value.clamped(with: ..<100) // 99.99999999999999
value.clamped(with: ...100) // 100
value.clamped(with: 1..<100) // 99.99999999999999
value.clamped(with: 1...100) // 100