使用结构进行转换时的对称性。什么是最佳做法?

时间:2014-11-19 18:19:07

标签: swift structure

我一直在玩Swift,我编码了一个明显的转换结构:

struct MutableAngle {
    var degrees : CGFloat
    var radians : CGFloat {
        return degrees * CGFloat(M_PI) / 180.0
    }

    init(inRadians : CGFloat) {
        degrees = inRadians * 180.0 / CGFloat(M_PI)
    }
    init(inDegrees : CGFloat) {
        degrees = inDegrees
    }
}

现在这很好但不优雅,因为它没有对称地对待度和弧度,尽管它确实给出了可变性。这实际上是一个应该被称为度数的结构,它可以提供弧度。例如,我可以写:

var angle : MutableAngle
angle.degrees = 45.0

但不是

var angle : MutableAngle
angle.radians = 0.75

这是最终版本:

struct Angle {
  let degrees : CGFloat
  let radians : CGFloat

  init(inRadians : CGFloat ) {
    radians = inRadians
    degrees = radians * CGFloat (180 / M_PI)
  }
  init(inDegrees : Float ) {
    degrees = inDegrees
    radians = degrees * CGFloat (M_PI / 180)
  }
}

使用如下:

var alpha = Angle(inDegrees: 45)
alpha.degrees // returns 45
alpha.radians // returns 0.7853982

// alpha.radians = 0.9  ... is now illegal with let constants
// must use constructor ... provided alpha was defined using 'var'
// i.e. the struct itself is mutable
alpha = Angle(inRadians: 0.9)
alpha.radians // returns 0.7853982
alpha.degrees // returns 45

从var切换到let使它变为可变/不可变取决于alpha的定义方式,我现在不得不使用好的构造函数。所以它的对称性。它还有一个优点,即每次我想使用弧度时都不需要计算。

2 个答案:

答案 0 :(得分:0)

这里有两件事:

  1. 在Swift中,您不需要为值类型设置单独的可变类型 - 由使用letvar实例化该类型的任何人处理。 / p>

  2. 您的radians计算属性只有一个getter - 你可以用setter和getter做你想做的事。

  3. 我的实施:

    struct Angle {
        var degrees : CGFloat = 0
        var radians : CGFloat {
            get {
                return degrees * CGFloat(M_PI) / 180.0
            }
            set {
                degrees = newValue * 180.0 / CGFloat(M_PI)
            }
        }
    
        init(inRadians : CGFloat) {
            radians = inRadians
        }
        init(inDegrees : CGFloat) {
            degrees = inDegrees
        }
    }
    

    用途:

    // immutable
    let angle = Angle(inDegrees: 180)
    println(angle.radians)
    // next line gives an error: can't assign to an immutable instance
    angle.radians = angle.radians * 2
    
    // mutable copy
    var mutableAngle = angle
    mutableAngle.degrees = 10
    println(mutableAngle.radians)
    // 0.1745...
    mutableAngle.radians = CGFloat(M_PI)
    println(mutableAngle.degrees)
    // 180.0
    

答案 1 :(得分:0)

一种可能的解决方案是使用enum及其相关值:

enum MutableAngle {
    case Radian(CGFloat)
    case Degree(CGFloat)

    init(radians:CGFloat) {
        self = .Radian(radians)
    }
    init(degrees:CGFloat) {
        self = .Degree(degrees)
    }

    var radians:CGFloat {
        get {
            switch self {
            case .Radian(let val): return val
            case .Degree(let val): return val * CGFloat(M_PI) / 180.0
            }
        }
        set {
            self = .Radian(newValue)
        }
    }
    var degrees:CGFloat {
        get {
            switch self {
            case .Degree(let val): return val
            case .Radian(let val): return val * 180.0 / CGFloat(M_PI)
            }
        }
        set {
            self = .Degree(newValue)
        }
    }
}

var angle = MutableAngle(radians: 1)
angle.degrees // -> 57.2957795130823
angle.degrees = 180
angle.radians // -> 3.14159265358979