Swift:选择一个随机枚举值

Seb*_*ger 22 random enums swift

我试图随机选择一个枚举值,这是我目前的尝试:

enum GeometryClassification {

    case Circle
    case Square
    case Triangle
    case GeometryClassificationMax

}
Run Code Online (Sandbox Code Playgroud)

和随机选择:

let shapeGeometry = ( arc4random() % GeometryClassification.GeometryClassificationMax ) as GeometryClassification
Run Code Online (Sandbox Code Playgroud)

然而,这无可救药地失败了.

我得到的错误如下:

'GeometryClassification' is not convertible to 'UInt32'
Run Code Online (Sandbox Code Playgroud)

关于如何解决这个问题的任何想法?

Nat*_*ook 30

我对你在那里的最后一个案子并不感到疯狂 - 似乎你.GeometryClassificationMax只是为了启用随机选择.在使用switch语句的任何地方,您都需要考虑该额外情况,并且它没有语义值.相反,静态方法enum可以确定最大值并返回随机情况,并且更易于理解和维护.

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)!
    }
}
Run Code Online (Sandbox Code Playgroud)

你现在可以enumswitch声明中用尽:

switch GeometryClassification.randomGeometry() {
case .Circle:
    println("Circle")
case .Square:
    println("Square")
case .Triangle:
    println("Triangle")
}
Run Code Online (Sandbox Code Playgroud)

  • 你是对的 - 我最终采用这种方法使其更具可读性.谢谢你的努力. (3认同)

Pha*_*nik 19

在Swift中,实际上有一个用于枚举的协议CaseIterable,如果将其添加到枚举中,则可以将所有用例作为一个集合引用.allCases为:

enum GeometryClassification: CaseIterable {

    case Circle
    case Square
    case Triangle

}
Run Code Online (Sandbox Code Playgroud)

然后您可以.allCases然后.randomElement()随机获得一个

let randomGeometry = GeometryClassification.allCases.randomElement()!
Run Code Online (Sandbox Code Playgroud)

需要进行强制展开,因为有可能枚举没有大小写,因此randomElement()将返回nil

  • .allCase 上的小写字母和缺少括号很重要。我不小心使用了“GeometryClassification.AllCases().randomElement()!”(谢谢自动完成功能),这是完全不同的,并导致了运行时错误。 (6认同)

ste*_*vex 8

因为你在enum类中,所以显式地使用random()方法引用最高值将不必每次都计算它们:

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)!
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*ndy 7

对于 Swift 5,有“ RandomNumberGenerator ”:

enum Weekday: CaseIterable {
    case sunday, monday, tuesday, wednesday, thursday, friday, saturday

    static func random<G: RandomNumberGenerator>(using generator: inout G) -> Weekday {
        return Weekday.allCases.randomElement(using: &generator)!
    }

    static func random() -> Weekday {
        var g = SystemRandomNumberGenerator()
        return Weekday.random(using: &g)
    }
}
Run Code Online (Sandbox Code Playgroud)


Ide*_*ete 5

您需要为枚举分配原始类型.如果使用整数类型,则枚举大小写值将从0开始自动生成:

enum GeometryClassification: UInt32 {  
    case Circle
    case Square
    case Triangle
    case GeometryClassificationMax
}
Run Code Online (Sandbox Code Playgroud)

"与C和Objective-C不同,Swift枚举成员在创建时不会被赋予默认的整数值." - 按此页面.指定整数类型可让它知道以通常的方式生成值.

然后你可以像这样生成随机值:

let randomEnum: GeometryClassification = GeometryClassification.fromRaw(arc4random_uniform(GeometryClassification.GeometryClassificationMax.toRaw()))!
Run Code Online (Sandbox Code Playgroud)

这是一个非常丑陋的调用,所有那些'fromRaw'和'toRaw'调用相当不优雅,所以我真的建议生成一个你想要的范围内的随机UInt32,然后从该值创建一个GeometryClassification:

GeometryClassification.fromRaw(someRandomUInt32)
Run Code Online (Sandbox Code Playgroud)