Considérer:
enum Line {
case Horizontal(CGFloat)
case Vertical(CGFloat)
}
let leftEdge = Line.Horizontal(0.0)
let leftMaskRightEdge = Line.Horizontal(0.05)
Comment puis-je accéder directement à la valeur associée de lefEdge
, sans utiliser une instruction switch?
let noIdeaHowTo = leftEdge.associatedValue + 0.5
Cela ne compile même pas!
J'ai jeté un coup d'œil à ces DONC questions mais aucune des réponses ne semble résoudre ce problème.
La ligne non compilable noIdeaHowTo
ci-dessus devrait vraiment être celle à une ligne, mais parce que la associated value
peut être de n'importe quel type, je n'arrive même pas à voir comment le code utilisateur pourrait même écrire une méthode get ou genericValue "générique" dans le leum lui-même.
Je me suis retrouvé avec ça, mais c'est dégoûtant, et j'ai besoin de revoir le code à chaque fois que j'ajoute/modifie un cas ...
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
}
}
}
}
Un pointeur n'importe qui?
Comme d'autres l'ont souligné, cela est désormais possible 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
Je pense que vous essayez peut-être d'utiliser enum
pour quelque chose auquel il n'était pas destiné. La façon d'accéder aux valeurs associées est en effet via switch
comme vous l'avez fait, l'idée étant que le switch
gère toujours chaque cas membre possible du enum
.
Différents membres de enum
peuvent avoir différentes valeurs associées (par exemple, vous pouvez avoir Diagonal(CGFloat, CGFloat)
et Text(String)
dans votre enum Line
), vous devez donc toujours confirmer le cas auquel vous avez affaire avant de pouvoir accéder à la valeur associée. Par exemple, considérez:
enum Line {
case Horizontal(CGFloat)
case Vertical(CGFloat)
case Diagonal(CGFloat, CGFloat)
case Text(String)
}
var myLine = someFunctionReturningEnumLine()
let value = myLine.associatedValue // <- type?
Comment pourriez-vous supposer obtenir la valeur associée de myLine
alors que vous pourriez avoir affaire à CGFloat
, String
ou twoCGFloat
s? C'est pourquoi vous avez besoin du switch
pour découvrir d'abord quel case
vous avez.
Dans votre cas particulier, il semble que vous feriez mieux d’utiliser un class
ou struct
pour Line
, qui pourrait alors stocker le CGFloat
et également avoir un enum
propriété pour Vertical
et Horizontal
. Ou vous pouvez modéliser Vertical
et Horizontal
comme classes distinctes, avec Line
étant un protocole (par exemple).
Vous pouvez utiliser une instruction guard pour accéder à la valeur associée, comme ceci.
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)
Pourquoi cela n'est pas possible est déjà répondu, ce n'est donc qu'un conseil. Pourquoi ne l'implémentez-vous pas ainsi. Je veux dire que les énumérations et les structures sont les deux types de valeurs.
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)
Avec Swift 2, il est possible d'obtenir la valeur associée (lecture seule) en utilisant la réflexion.
Pour faciliter cela, ajoutez simplement le code ci-dessous à votre projet et étendez votre énumération avec le protocole 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)
}
}
}
Ensuite, vous pouvez accéder à la valeur .asociated avec un code comme celui-ci:
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)
}
Le code ci-dessus provient de mon projet https://github.com/evermeer/EVReflectionhttps://github.com/evermeer/EVReflection