2014-10-08 13 views
14

Próbuję losowo wybrał wartość enum, to moja obecna próba:Swift: Wybrał losową wartość wyliczenia

enum GeometryClassification { 

    case Circle 
    case Square 
    case Triangle 
    case GeometryClassificationMax 

} 

i losowy wybór:

let shapeGeometry = (arc4random() % GeometryClassification.GeometryClassificationMax) as GeometryClassification 

to jednak nie zdało egzaminu.

pojawiają się błędy takie jak:

'GeometryClassification' is not convertible to 'UInt32' 

wszelkich pomysłów, jak rozwiązać to?

Odpowiedz

22

ja nie szaleję ostatnim przypadku nie - wydaje się, że jesteś w tym .GeometryClassificationMax wyłącznie do umożliwienia losowo wybór. Będziesz musiał uwzględnić ten dodatkowy przypadek wszędzie, gdzie używasz instrukcji switch i nie ma wartości semantycznej. Zamiast tego, statyczna metoda na enum może określić maksymalną wartość i zwrócić przypadek losowy i będzie znacznie bardziej zrozumiała i możliwa do utrzymania.

enum GeometryClassification: UInt32 { 
    case Circle 
    case Square 
    case Triangle 

    private static let _count: GeometryClassification.RawValue = { 
     // find the maximum enum value 
     var maxValue: UInt32 = 0 
     while let _ = GeometryClassification(rawValue: maxValue) { 
      maxValue += 1 
     } 
     return maxValue 
    }() 

    static func randomGeometry() -> GeometryClassification { 
     // pick and return a new value 
     let rand = arc4random_uniform(_count) 
     return GeometryClassification(rawValue: rand)! 
    } 
} 

i obecnie można wyczerpać enum w switch stwierdzeniem:

switch GeometryClassification.randomGeometry() { 
case .Circle: 
    println("Circle") 
case .Square: 
    println("Square") 
case .Triangle: 
    println("Triangle") 
} 
+3

masz rację - podszedłem z takim podejściem, aby było bardziej czytelne. dziękuję za trud. –

+0

'++ maxValue' będzie przestarzałe w Swift 3. W jaki sposób zmieniłbyś to w swoim kodzie? – Cesare

+0

@Cesare: Możesz przesuwać inkrement w pętli 'while'. –

5

Musisz przypisać typu surowego do swojego wyliczenia. Jeśli używasz typu INTEGER, wówczas wartości case wyliczenie będzie generowane automatycznie zaczynając od 0:

enum GeometryClassification: UInt32 { 
    case Circle 
    case Square 
    case Triangle 
    case GeometryClassificationMax 
} 

„W przeciwieństwie do C i Objective-C, Swift członkowie wyliczenie nie jest przypisana wartość domyślna całkowitą gdy są one tworzone . " - według strony this. Określenie typu integer pozwala mu wygenerować wartości w zwykły sposób.

Następnie można wygenerować losową wartość takiego:

let randomEnum: GeometryClassification = GeometryClassification.fromRaw(arc4random_uniform(GeometryClassification.GeometryClassificationMax.toRaw()))! 

To jest strasznie brzydki połączenie, a wszystkie te „fromRaw” i nazywa „toRaw” mają dość nieeleganckie, więc naprawdę polecam generowanie losowo UInt32 który mieści się w przedziale chcesz, potem tworząc GeometryClassification od tej wartości:

GeometryClassification.fromRaw(someRandomUInt32) 
+0

Nie ma potrzeby przypisywania określonych wartości w tym przypadku; będą automatycznie generowane począwszy od '0'. Część, którą zacytowałeś w dokumentacji, jest tylko wtedy, gdy 'enum' nie ma w surowym typie całkowitym. W dalszej części tego samego dokumentu: "Gdy liczby całkowite są używane dla wartości nieprzetworzonych, automatycznie się zwiększają, jeśli nie podano wartości dla niektórych elementów wyliczeniowych." –

+0

ten sam błąd pozostaje smutny:/ –

+0

@ SebastianFlückiger będziesz musiał utworzyć "GeometryClassification" od wartości surowej zwróconej z 'arc4random':' let shapeGeometry = GeometryClassification (rawValue: (arc4random()% GeometryClassification.GeometryClassificationMax.rawValue)) ' –

7

Skoro jesteś wewnątrz klasy enum, posiadające metody random() Odniesienie najwyższą wartość wyraźnie wyeliminuje konieczności liczyć je za każdym razem:

enum GeometryClassification: UInt32 { 
    case Circle 
    case Square 
    case Triangle 

    static func random() -> GeometryClassification { 
     // Update as new enumerations are added 
     let maxValue = Triangle.rawValue 

     let rand = arc4random_uniform(maxValue+1) 
     return GeometryClassification(rawValue: rand)! 
    } 
} 
+0

To nie działa od Swift 1.2. Chce wartości raw przypisanej do enum. To z kolei oznacza, że ​​działa tylko z wyliczeniami o typie Int rawValue. – BadmintonCat

+0

Miałem literówkę na moim kodzie, zwracałem niewłaściwy typ. – stevex

1

Oto mój Swift 1,2 odbioru:

enum GeometryClassification : Int { 
    case Circle = 0 
    case Square = 1 
    case Triangle = 2 

    static func random() -> GeometryClassification { 
     let min = MutationType.Circle.rawValue 
     let max = MutationType.Triangle.rawValue 
     let rand = Int.random(min: min, max: max) // Uses ExSwift! 
     return self(rawValue: rand)! 
    } 
} 
Powiązane problemy