web-dev-qa-db-ja.com

switchステートメントの外でSwift enum関連付けられた値にアクセスする方法

考慮してください:

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

これもコンパイルされません!

これら[〜#〜] so [〜#〜]questions を見ましたが、この問題に対処する答えはありません。

上記のnoIdeaHowToの非コンパイル行は実際にはその1行でなければなりませんが、associated valueはどのタイプでもかまいませんが、ユーザーコードがle enum自体に「generic」getまたはrelatedValueメソッドを書き込む方法を見ることさえできません。

私はこれで終わったが、それはひどく、ケースを追加/変更するたびにコードを再訪する必要がある...

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

ポインタはありますか?

45
verec

他の人が指摘したように、これはSwift 2:

import CoreGraphics

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

let min = Line.Horizontal(0.0)
let mid = Line.Horizontal(0.5)
let max = Line.Horizontal(1.0)

func doToLine(line: Line) -> CGFloat? {
    if case .Horizontal(let value) = line {
        return value
    }
    return .None
}

doToLine(min) // prints 0
doToLine(mid) // prints 0.5
doToLine(max) // prints 1
65
verec

意図していないものにenumを使用しようとしているのかもしれません。関連付けられた値にアクセスする方法は、実際にswitchを使用することです。switchは、enumの可能なメンバーケースを常に処理するという考え方です。

enumの異なるメンバーは、異なる関連する値を持つことができます(たとえば、_enum Line_にDiagonal(CGFloat, CGFloat)Text(String)を含めることができます)。関連する値にアクセスする前に。たとえば、次のことを考慮してください。

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

myLineCGFloat、またはtwoStringsを処理している可能性があるときに、CGFloatから関連する値を取得するにはどうすればよいでしょうか?これが、どのswitchがあるかを最初に発見するためにcaseが必要な理由です。

あなたの特定のケースでは、classstructまたはLineを使用するとよいかもしれません。これは、CGFloatを格納し、enumおよびVerticalHorizontalプロパティも持つ場合があります。または、VerticalHorizontalを別々のクラスとしてモデル化することもできます。たとえば、Lineをプロトコルにします。

8
Arkku

このように、guardステートメントを使用して関連する値にアクセスできます。

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

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

guard case .Horizontal(let leftEdgeValue) = leftEdge else { fatalError() }

print(leftEdgeValue)
6

なぜこれが不可能なのかはすでに答えられているので、これは単なるアドバイスです。このように実装してみませんか。列挙型と構造体はどちらも値型です。

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)
3
DevAndArtist

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/EVReflectionhttps://github.com/evermeer/EVReflection

2
Edwin Vermeer