Accessing an Enumeration Association Value in Swift

Accessing an Enumeration association value in Swift

The value is associated to an instance of the enumeration. Therefore, to access it without a switch, you need to make a getter and make it available explicitly. Something like below:

enum Number {
case int(Int)
case float(Float)

func get() -> NSNumber {
switch self {
case .int(let num):
return num
case .float(let num):
return num
}
}
}

var vInteger = Number.int(10)
var vFloat = Number.float(10.5)

println(vInteger.get())
println(vFloat.get())

Maybe in the future something like that may be automatically created or a shorter convenience could be added to the language.

How to access a Swift enum associated value outside of a switch statement

As others have pointed out, this is now kind of possible in 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

Get enum parameter value

Inside ButtonType enum, declare property like this:

enum ButtonType {
...
var value: String {
switch self {
case .number(let number): return number
case .clear(let clearValue): return clearValue
case .backspace(let backSpaceValue): return backSpaceValue
}
}
}

Accessing a non raw type enumerations case values?

You need to use a switch here:

switch position {
case .top(let f):
// use f
case .middle(let f):
// use f
case .bottom(let f):
// use f
}

If you want it as an expression, you can do something like:

// you can assign the below to a variable or whatever
// let value =
{ () -> CGFloat in
switch position {
case .top(let f):
return f
case .middle(let f):
return f
case .bottom(let f):
return f
}
}()

However, I think the best solution is to redesign your types. It seems like there will always be a CGFloat associated with every case of your enum. Why not use a struct composing a simple enum and a CGFloat?

enum RelativeCardPosition {
case top
case middle
case bottom
}

struct CardPosition {
let relativeCardPosition: RelativeCardPosition
let offset: CGFloat

static func top(_ offset: CGFloat) -> CardPosition {
CardPosition(relativeCardPosition: .top, offset: offset)
}

static func middle(_ offset: CGFloat) -> CardPosition {
CardPosition(relativeCardPosition: .middle, offset: offset)
}

static func bottom(_ offset: CGFloat) -> CardPosition {
CardPosition(relativeCardPosition: .bottom, offset: offset)
}
}

Then you can easily access the number via position.offset.

How to access second-level nested enum passed as parameter in Swift

You would need a giant switch statement to extract the cut styles,

for ingredient in salad {
let cutStyle: CutStyle?
switch ingredient {
case .lettuce(let cut):
cutStyle = cut
case .tomatoes(let cut):
cutStyle = cut
case .onions(let cut):
cutStyle = cut
case .cucumbers(let cut):
cutStyle = cut
case .dressing:
cutStyle = nil
}
print(cutStyle)
}

I think you could have modelled your salad better. Here are two alternative designs that allows you to access the cut style more easily.

One way is to make a SaladIngredient struct that composes a cut style and an ingredient:

struct SaladIngredient {
enum Ingredient {
case lettuce
case tomatoes
case onions
case cucumbers
case dressing
}

enum CutStyle {
case diced
case chopped
case minced
case grated
}

let ingredient: Ingredient
let cutStyle: CutStyle?
}
func shareSalad(my salad: [SaladIngredient]) {
print("My salad contains:")
for ingredient in salad {
if let cutStyle = ingredient.cutStyle {
print(cutStyle)
}
}
}

The disadvantage of this is that it's harder to enforce the rule that dressings don't have a cut style.

Alternatively, collapse all those enum cases with a cut style into one case:

enum SaladIngredient {
enum Ingredient {
case lettuce
case tomatoes
case onions
case cucumbers
}
enum CutStyle {
case diced
case chopped
case minced
case grated
}
case cuttable(Ingredient, cutStyle: CutStyle)
case dressing
}
func shareSalad(my salad: [SaladIngredient]) {
print("My salad contains:")
for ingredient in salad {
if case .cuttable(_, cutStyle: let cutStyle) = ingredient {
print(cutStyle)
}
}
}

The disadvantage of this is that you are making .dressing a totally different "type" of thing from lettuce, tomatoes and others.

How to compare enum with associated values by ignoring its associated value in Swift?

Edit: As Etan points out, you can omit the (_) wildcard match to use this more cleanly.


Unfortunately, I don't believe that there's an easier way than your switch approach in Swift 1.2.

In Swift 2, however, you can use the new if-case pattern match:

let number = CardRank.Number(5)
if case .Number(_) = number {
// Is a number
} else {
// Something else
}

If you're looking to avoid verbosity, you might consider adding an isNumber computed property to your enum that implements your switch statement.

How to make a Swift enum with associated values equatable

SE-0185 Synthesizing Equatable and Hashable conformance has been implemented in Swift 4.1, so that it suffices do declare conformance to the protocol (if all members are Equatable):

enum ViewModel: Equatable {
case heading(String)
case options(id: String, title: String, enabled: Bool)
}

For earlier Swift versions, a convenient way is to use that tuples can be compared with ==.

You many also want to enclose the compatibility code in a Swift version check, so that the automatic synthesis is used once the project is updated to Swift 4.1:

enum ViewModel: Equatable {
case heading(String)
case options(id: String, title: String, enabled: Bool)

#if swift(>=4.1)
#else
static func ==(lhs: ViewModel, rhs: ViewModel) -> Bool {
switch (lhs, rhs) {
case (let .heading(lhsString), let .heading(rhsString)):
return lhsString == rhsString
case (let .options(lhsId, lhsTitle, lhsEnabled), let .options(rhsId, rhsTitle, rhsEnabled)):
return (lhsId, lhsTitle, lhsEnabled) == (rhsId, rhsTitle, rhsEnabled)
default:
return false
}
}
#endif
}


Related Topics



Leave a reply



Submit