with values switch parameter enum computed swift enums

values - switch self swift



Cómo acceder a un valor asociado de Swift enum fuera de una sentencia switch (5)

Como han señalado otros, esto ahora es posible en 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

Considerar:

enum Line { case Horizontal(CGFloat) case Vertical(CGFloat) } let leftEdge = Line.Horizontal(0.0) let leftMaskRightEdge = Line.Horizontal(0.05)

¿Cómo puedo acceder, por ejemplo, lefEdge valor asociado de lefEdge , directamente, sin usar una instrucción switch?

let noIdeaHowTo = leftEdge.associatedValue + 0.5

¡Esto ni siquiera compila!

Eché un vistazo a these questions SO questions pero ninguna de las respuestas parece abordar este problema.

La línea de noIdeaHowTo no compila arriba debería ser realmente de una sola línea, pero como el associated value puede ser de cualquier tipo, ni siquiera puedo ver cómo el código de usuario podría escribir incluso un método "genérico" get o asociadoValue en leumum mismo.

Terminé con esto, pero es asqueroso, y necesito que vuelva a visitar el código cada vez que agregue / modifique un caso ...

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

Cualquier puntero a alguien?


Con Swift 2 es posible obtener el valor asociado (solo lectura) utilizando la reflexión.

Para hacerlo más fácil, simplemente agregue el código a continuación a su proyecto y amplíe su enumeración con el protocolo asociado a EVA.

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

Luego puede acceder al valor asociado con un código como este:

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

El código anterior es de mi proyecto https://github.com/evermeer/EVReflection https://github.com/evermeer/EVReflection


Creo que puedes estar tratando de usar enum para algo para lo que no estaba destinado. La forma de acceder a los valores asociados es a través del switch como lo ha hecho, con la idea de que el switch siempre maneje cada posible caso miembro de la enum .

Diferentes miembros de la enum pueden tener diferentes valores asociados (por ejemplo, podría tener Diagonal(CGFloat, CGFloat) y Text(String) en su enum Line ), por lo que siempre debe confirmar qué caso está tratando antes de poder acceder al valor asociado. Por ejemplo, considere:

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

¿Cómo podría suponer obtener el valor asociado de myLine cuando podría estar CGFloat con CGFloat , String o dos CGFloat s? Es por eso que necesita el switch para descubrir primero qué case tiene.

En su caso particular, parece que podría estar mejor con una class o struct para Line , que luego podría almacenar el CGFloat y también tener una propiedad enum para Vertical y Horizontal . O bien, podría modelar Vertical y Horizontal como clases separadas, siendo Line un protocolo (por ejemplo).


Por qué esto no es posible ya está respondido, así que esto es solo un consejo. ¿Por qué no lo implementas así? Me refiero a las enumeraciones y las estructuras son ambos tipos de valores.

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)


Puede usar una declaración de guardia para acceder al valor asociado, así.

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)