我可以将 Swift 枚举中的不同关联值绑定到同一个 var 吗?

Tra*_*ggs 4 enums swift swift2

我做了一个小“角度”枚举,以便我可以使用不同的可互换角度格式进行编程:

enum Angle {
    case Radians(CGFloat)
    case Degrees(CGFloat)
    case Rotations(CGFloat)
}
Run Code Online (Sandbox Code Playgroud)

我发现这种方法有一些冗余的样板代码。例如,我想添加一个刚刚返回原始底层关联浮点数的计算变量:

var raw:CGFloat {
    switch self {
    case let .Radians(value):
        return value
    case let .Degrees(value):
        return value
    case let .Rotations(value):
        return value
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图将其更改为:

case .Radians(let value), .Degrees(let value):
    return value
Run Code Online (Sandbox Code Playgroud)

我希望它足够聪明,意识到它只会解决一场比赛,所以冲突是可以忽略的。但是没有这样的设备。编译器说它不能解决两者之间的冲突let value语句。

那么,是否有一些我还没有在 Swift 枚举中发现的惯用聪明之处,可以让我不必在那里重复太多?

另一个类似的例子是当我实现这个*功能时:

func * (lhs:Angle, rhs:CGFloat) -> Angle {
    switch lhs {
    case .Radians:
        return .Radians(lhs.raw * rhs)
    case .Degrees:
        return .Degrees(lhs.raw * rhs)
    case .Rotations:
        return .Rotations(lhs.raw * rhs)
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎应该有一种更简单的表达方式:“使用我的关联值乘以标量参数制作相同的枚举类型”。

(我不确定我在这个问题上有一个好的标题,请随时改进/提出更好的建议)

Kam*_*xom 5

这是一个有趣的例子:枚举在某种程度上不是正确的数据类型,因为值既不是弧度也不是度数,两者都只是角度而不是真正不同的东西。还typealias Radians = Double不会工作,因为没有单位安全。

也许你可以使用这样的东西:

import Darwin

struct Angle {
    enum Unit {
        case Radians
        case Degrees
        case Rotations

        var radiansFactor : Double {
            switch self {
            case Radians: return 1
            case Degrees: return 180.0 / M_PI
            case Rotations: return 1 / 2 / M_PI
            }
        }
    }

    var unit : Unit {
        didSet {
            value /= oldValue.radiansFactor
            value *= unit.radiansFactor
        }
    }
    var value : Double
}

func * (var lhs: Angle, rhs: Double) -> Angle {
    lhs.value *= rhs
    return lhs
}

var angle = Angle(unit: .Degrees, value: 180)

angle.value             // 180.0
angle.unit = .Radians
angle.value             // 3.141592...
angle.unit = .Rotations
angle.value             // 0.5
Run Code Online (Sandbox Code Playgroud)

哦,至于你原来的问题的答案:不,你不能。