Swift中如何定义类似CGFloat.infinity的CGFloat自定义静态值
实现方案
CGFloat.infinity打印为inf的本质,是它属于IEEE 754浮点数标准定义的特殊值,Swift对这类特殊值的打印逻辑做了内置实现。我们没法给浮点数原生新增特殊值类型,但可以利用带自定义载荷的安静NaN(非数)实现完全一致的效果:
- IEEE 754标准允许NaN值携带自定义载荷信息,我们可以指定一个全局唯一的NaN位模式作为
cool的底层存储 - 重写CGFloat的字符串描述逻辑,识别到这个特定位模式时返回
cool,其余场景完全保留原有打印行为,不影响普通数值、inf、普通NaN的原有表现
完整代码
import CoreGraphics extension CGFloat { // 自定义cool值的唯一NaN载荷,用"COOL"对应的十六进制值,避免和系统生成的NaN冲突 private static let coolPayload: UInt64 = 0x434F4F4C static let cool: CGFloat = { var basePattern = CGFloat.quietNaN.bitPattern if MemoryLayout<CGFloat>.size == 8 { // 64位环境下CGFloat底层为Double,载荷占低51位 basePattern = (basePattern & ~0x7FFFFFFFFFFFF) | coolPayload } else { // 32位环境下CGFloat底层为Float,载荷占低22位 basePattern = (basePattern & ~0x3FFFFF) | UInt32(coolPayload & 0x3FFFFF) } return CGFloat(bitPattern: basePattern) }() public var description: String { // 识别自定义cool值 if isNaN { let currentPayload: UInt64 if MemoryLayout<CGFloat>.size == 8 { currentPayload = bitPattern & 0x7FFFFFFFFFFFF } else { currentPayload = UInt64(bitPattern & 0x3FFFFF) } if currentPayload == Self.coolPayload { return "cool" } } // 非cool值走原生打印逻辑,不破坏原有行为 return String(describing: (self as NSNumber).doubleValue) } }
测试验证
func test() { let value1: CGFloat = .infinity let value2: CGFloat = .cool let value3: CGFloat = 0 let value4: CGFloat = .nan print(value1) // 输出 inf print(value2) // 输出 cool print(value3) // 输出 0.0 print(value4) // 输出 nan }
说明
CGFloat.cool是实打实的CGFloat类型,不是包装类型或者字符串,可以直接参与所有CGFloat支持的运算- 由于其本质是NaN值,参与运算后的结果和系统原生NaN、inf的行为逻辑保持一致
- 只要自定义的载荷值不与系统生成的NaN载荷冲突,就不会出现识别错误的问题
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

