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

时间:2015-09-28 16:17:27

标签: swift enums swift2

我做了一点" Angle"枚举,以便我可以使用不同的可互换角度格式进行编程:

enum Angle {
    case Radians(CGFloat)
    case Degrees(CGFloat)
    case Rotations(CGFloat)
}

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

var raw:CGFloat {
    switch self {
    case let .Radians(value):
        return value
    case let .Degrees(value):
        return value
    case let .Rotations(value):
        return value
    }
}

我试图将其改为:

case .Radians(let value), .Degrees(let value):
    return value

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

因此,有一些惯用的聪明才智,我还没有发现Swift enum,但这样做会让我不必在那里重复自己吗?

另一个类似的例子是我实现了*函数:

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)
    }
}

似乎应该有一种更简单的方式来表达:"使用我的相关值生成相同的枚举类型乘以标量参数"。

(我不确定我在这个问题上有一个好头衔,随时改善/建议更好)

3 个答案:

答案 0 :(得分:2)

这是一个有趣的案例:enum以某种方式不是正确的数据类型,因为该值不是弧度或度数,两者都只是角度而不是真正不同的东西。另外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

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

答案 1 :(得分:2)

在较新版本的Swift中,如果值的类型相同,则现在可以实现:

enum Foo {
    case bar(Int),  bas(Int)
}

var this = .random() ? Foo.bar(5) : Foo.bas(5)
switch this {
    case .bar(let foo), .bas(let foo): print(foo) // Always prints: 5
}

您甚至可以执行以下操作:

enum Foo {
    case bar(Int, Int),  bas(Int, Int)
}

var this = .random() ? Foo.bar(5) : Foo.bas(5)
switch this {
    case .bar(let foo, let bat), .bas(let foo, let bat): print(foo, bat) // Always prints: 5 5
}

答案 2 :(得分:0)

基于@Kametrixom的回应,我最终为这个特殊的"角度"做了什么?建模问题如下:

import UIKit
import CoreGraphics

let Tau = CGFloat(2 * M_PI)

struct Angle {
    enum Unit:CGFloat {
        case Radians = 1.0
        case Degrees = 57.29577951309314 // 360.0 / Tau
        case Rotations = 6.28318530717959 //Tau
    }
    var raw:CGFloat = 0.0
    var unit:Unit = .Radians

    func convert(anotherUnit:Unit) -> Angle {
        return self.unit == anotherUnit ? self : Angle(raw: self.raw * self.unit.rawValue / anotherUnit.rawValue, unit: anotherUnit)
    }

    var radians:Angle {
        return self.convert(.Radians)
    }

    var degrees:Angle {
        return self.convert(.Degrees)
    }

    var rotations:Angle {
        return self.convert(.Rotations)
    }

    var cos:CGFloat {
        return CoreGraphics.cos(self.radians.raw)
    }

    var sin:CGFloat {
        return CoreGraphics.sin(self.radians.raw)
    }

    var half:Angle {
        return self / 2
    }
}

extension Angle: Comparable {}

func < (lhs:Angle, rhs:Angle) -> Bool {
    return lhs.radians.raw < rhs.radians.raw
}

func == (lhs:Angle, rhs:Angle) -> Bool {
    return lhs.radians.raw == rhs.radians.raw
}

func + (lhs:Angle, rhs:Angle) -> Angle {
    let other = rhs.convert(lhs.unit)
    return Angle(raw: lhs.raw + other.raw, unit: lhs.unit)
}

func - (lhs:Angle, rhs:Angle) -> Angle {
    let other = rhs.convert(lhs.unit)
    return Angle(raw: lhs.raw - other.raw, unit: lhs.unit)
}

func * (lhs:CGFloat, rhs:Angle) -> Angle {
    return rhs * lhs
}

func * (lhs:Angle, rhs:CGFloat) -> Angle {
    return Angle(raw: lhs.raw * rhs, unit: lhs.unit)
}

func / (lhs:Angle, rhs:CGFloat) -> Angle {
    return Angle(raw: lhs.raw / rhs, unit: lhs.unit)
}