如何在switch语句之外访问Swift枚举关联值

时间:2015-07-11 16:13:57

标签: swift enums

考虑:

enum Line {
    case    Horizontal(CGFloat)
    case    Vertical(CGFloat)
}

let leftEdge             =  Line.Horizontal(0.0)
let leftMaskRightEdge    =  Line.Horizontal(0.05)

如何在不使用switch语句的情况下直接访问lefEdge的关联值?

let noIdeaHowTo          = leftEdge.associatedValue + 0.5

这甚至无法编译!

我查看了these SO questions,但似乎没有一个答案可以解决这个问题。

上面的noIdeaHowTo非编译行应该是一行的,但因为associated value可以是任何类型,我甚至看不到用户代码如何写一个"通用" le enum本身中的get或associatedValue方法。

我最终得到了这个,但这很糟糕,每次我添加/修改案例时都需要我重新访问代码......

enum Line {
    case    Horizontal(CGFloat)
    case    Vertical(CGFloat)

    var associatedValue: CGFloat {
        get {
            switch self {
                case    .Horizontal(let value): return value
                case    .Vertical(let value): return value
            }
        }
    }
}

任何人指针?

5 个答案:

答案 0 :(得分:61)

正如其他人所指出的,现在Swift 2中有可能实现这一点:

includes

答案 1 :(得分:8)

我认为您可能会尝试将enum用于不适合的事情。访问相关值的方法确实是通过switch完成的,我的想法是switch始终处理enum的每个可能的成员案例。

enum的不同成员可以有不同的关联值(例如,Diagonal(CGFloat, CGFloat)中可以有Text(String)enum Line,因此您必须始终确认哪个案例在您可以访问相关值之前,您正在处理。例如,考虑:

enum Line {
    case Horizontal(CGFloat)
    case Vertical(CGFloat)
    case Diagonal(CGFloat, CGFloat)
    case Text(String)
}
var myLine = someFunctionReturningEnumLine()
let value = myLine.associatedValue // <- type?

当您处理myLineCGFloat两个 String时,您如何设定从CGFloat获取相关值? S'这就是您需要switch首先发现您拥有case的原因。

在您的特定情况下,您可能会感觉classstruct Line可能会更好,这可能会存储CGFloat并且还会{ {1}}和enum的{​​1}}属性。或者您可以将VerticalHorizontal建模为单独的类,Vertical是一个协议(例如)。

答案 2 :(得分:4)

您可以使用guard语句访问相关值,如下所示。

EXPLAIN SELECT COUNT(*) FROM (SELECT DISTINCT id FROM users) u;

答案 3 :(得分:3)

为什么这不可能已经得到解答,所以这只是一个建议。你为什么不这样实现呢。我的意思是枚举和结构都是值类型。

enum Orientation {
    case Horizontal
    case Vertical
}

struct Line {

    let orientation : Orientation
    let value : CGFloat

    init(_ orientation: Orientation, _ value: CGFloat) {

        self.orientation = orientation
        self.value = value
    }
} 

let x = Line(.Horizontal, 20.0)

// if you want that syntax 'Line.Horizontal(0.0)' you could fake it like this

struct Line {

    let orientation : Orientation
    let value : CGFloat

    private init(_ orientation: Orientation, _ value: CGFloat) {

        self.orientation = orientation
        self.value = value
    }

    static func Horizontal(value: CGFloat) -> Line { return Line(.Horizontal, value) }
    static func Vertical(value: CGFloat) -> Line { return Line(.Vertical, value) }
}

let y = Line.Horizontal(20.0)

答案 4 :(得分:2)

使用Swift 2,可以使用反射获得相关值(只读)。

为了更容易,只需将下面的代码添加到您的项目中,并使用EVAssociated协议扩展您的枚举。

    public protocol EVAssociated {
    }

    public extension EVAssociated {
        public var associated: (label:String, value: Any?) {
            get {
                let mirror = Mirror(reflecting: self)
                if let associated = mirror.children.first {
                    return (associated.label!, associated.value)
                }
                print("WARNING: Enum option of \(self) does not have an associated value")
                return ("\(self)", nil)
            }
        }
    }

然后您可以使用以下代码访问.asociated值:

    class EVReflectionTests: XCTestCase {
            func testEnumAssociatedValues() {
                let parameters:[EVAssociated] = [usersParameters.number(19),
usersParameters.authors_only(false)]
            let y = WordPressRequestConvertible.MeLikes("XX", Dictionary(associated: parameters))
            // Now just extract the label and associated values from this enum
            let label = y.associated.label
            let (token, param) = y.associated.value as! (String, [String:Any]?)

            XCTAssertEqual("MeLikes", label, "The label of the enum should be MeLikes")
            XCTAssertEqual("XX", token, "The token associated value of the enum should be XX")
            XCTAssertEqual(19, param?["number"] as? Int, "The number param associated value of the enum should be 19")
            XCTAssertEqual(false, param?["authors_only"] as? Bool, "The authors_only param associated value of the enum should be false")

            print("\(label) = {token = \(token), params = \(param)")
        }
    }

    // See http://github.com/evermeer/EVWordPressAPI for a full functional usage of associated values
    enum WordPressRequestConvertible: EVAssociated {
        case Users(String, Dictionary<String, Any>?)
        case Suggest(String, Dictionary<String, Any>?)
        case Me(String, Dictionary<String, Any>?)
        case MeLikes(String, Dictionary<String, Any>?)
        case Shortcodes(String, Dictionary<String, Any>?)
    }

    public enum usersParameters: EVAssociated {
        case context(String)
        case http_envelope(Bool)
        case pretty(Bool)
        case meta(String)
        case fields(String)
        case callback(String)
        case number(Int)
        case offset(Int)
        case order(String)
        case order_by(String)
        case authors_only(Bool)
        case type(String)
    }

上面的代码来自我的项目https://github.com/evermeer/EVReflection https://github.com/evermeer/EVReflection