Swift占星应用自定义整型格式化:位置数值循环进位实现需求
实现方案
要不要创建自定义类型
非常建议封装为独立自定义类型。原生Int类型不具备你需要的范围自动校验、循环转换、进位逻辑,封装后可以保证所有Position实例的取值永远符合业务规则,不需要上层业务重复写校验逻辑,大幅降低出错概率。
核心实现思路
- 内部用0基数值存储,简化模运算逻辑,对外暴露的属性按需转换为业务要求的1基(星座1~12)即可
- 统一封装归一化方法,所有属性修改、数值运算后统一调用,一次性处理进位、范围循环逻辑
- 遵守
CustomStringConvertible协议实现自定义格式化输出
代码实现
struct Position { // 内部0基存储 简化模运算 private var _sign: Int private var _degrees: Int private var _minutes: Int // 对外暴露的业务属性 符合占星规则 var sign: Int { get { _sign + 1 } set { _sign = newValue - 1 normalize() } } var degrees: Int { get { _degrees } set { _degrees = newValue normalize() } } var minutes: Int { get { _minutes } set { _minutes = newValue normalize() } } init(sign: Int, degrees: Int, minutes: Int) { _sign = sign - 1 _degrees = degrees _minutes = minutes normalize() } // 统一处理进位、范围循环逻辑 同时支持正负值处理 private mutating func normalize() { // 处理分钟进位 var minutesCarry = _minutes / 60 _minutes = _minutes % 60 if _minutes < 0 { _minutes += 60 minutesCarry -= 1 } // 处理度数进位 _degrees += minutesCarry var degreesCarry = _degrees / 30 _degrees = _degrees % 30 if _degrees < 0 { _degrees += 30 degreesCarry -= 1 } // 处理星座循环 _sign += degreesCarry _sign = _sign % 12 if _sign < 0 { _sign += 12 } } // 快捷加减方法 可按需扩展 mutating func add(minutes: Int) { _minutes += minutes normalize() } mutating func add(degrees: Int) { _degrees += degrees normalize() } } // 格式化输出实现 extension Position: CustomStringConvertible { var description: String { "\(sign) \(degrees)’ \(minutes)\"" } }
效果验证
- 非法值自动转换:
Position(sign: 13, degrees: 30, minutes: 60)输出为2 1’ 0",符合循环规则 - 进位逻辑验证:
var pos = Position(sign: 12, degrees: 29, minutes: 59); pos.add(minutes: 1)输出为1 0’ 0",符合进位要求(如果需要展示为0 0 0,只需将sign的getter改为返回_sign即可)
可选优化
如果需要更强的取值控制,可以将sign/degrees/minutes的setter私有化,只开放add系列方法修改数值,完全避免上层直接赋值错误值。也可以重载+/+=等运算符,让数值运算的用法和原生类型保持一致。
内容的提问来源于stack exchange,提问作者bennetts_
相关产品推荐
相关产品推荐

