Random 如何选择随机枚举值
我正在尝试随机选择一个枚举值:Random 如何选择随机枚举值,random,swift,enums,Random,Swift,Enums,我正在尝试随机选择一个枚举值: enum GeometryClassification { case Circle case Square case Triangle case GeometryClassificationMax } 以及随机选择: let shapeGeometry = ( arc4random() % GeometryClassification.GeometryClassificationMax ) as GeometryClassif
enum GeometryClassification {
case Circle
case Square
case Triangle
case GeometryClassificationMax
}
以及随机选择:
let shapeGeometry = ( arc4random() % GeometryClassification.GeometryClassificationMax ) as GeometryClassification
但它失败了
我会遇到如下错误:
'GeometryClassification' is not convertible to 'UInt32'
如何解决此问题?您需要为枚举分配一个原始类型。如果使用整数类型,则枚举案例值将从0开始自动生成:
enum GeometryClassification: UInt32 {
case Circle
case Square
case Triangle
case GeometryClassificationMax
}
Per:
与C和Objective-C不同,Swift枚举成员在创建时未指定默认整数值
指定整数类型可以让它知道如何以通常的方式生成值
然后可以生成如下所示的随机值:
let randomEnum: GeometryClassification = GeometryClassification.fromRaw(arc4random_uniform(GeometryClassification.GeometryClassificationMax.toRaw()))!
这是一个非常丑陋的调用,所有这些fromRaw
和toRaw
调用都非常不优雅,因此我建议首先生成一个在您想要的范围内的随机UInt32,然后根据该值创建一个Geometryclassion
:
GeometryClassification.fromRaw(someRandomUInt32)
自编写此答案以来,Swift获得了一些新功能,提供了更好的解决方案—请参见“”
我对你的最后一个案例不感兴趣——似乎你加入了
.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)!
}
}
现在,您可以在开关
语句中耗尽枚举
:
switch GeometryClassification.randomGeometry() {
case .Circle:
println("Circle")
case .Square:
println("Square")
case .Triangle:
println("Triangle")
}
由于您在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)!
}
}
以下是我的Swift 1.2拍摄:
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)!
}
}
您可以将所有值放入数组并生成随机值
extension GeometryClassification {
static func random() -> GeometryClassification {
let all: [GeometryClassification] = [.Circle,
.Square,
.Triangle,
.GeometryClassificationMax]
let randomIndex = Int(arc4random()) % all.count
return all[randomIndex]
}
}
在Swift中,实际上有一个用于枚举的协议,名为
caseitrable
,如果您将其添加到枚举中,您可以将所有案例作为集合引用。所有案例
,如下所示:
enum GeometryClassification: CaseIterable {
case Circle
case Square
case Triangle
}
然后你可以.allCases
然后.randomElement()
得到一个随机的
let randomGeometry = GeometryClassification.allCases.randomElement()!
强制展开是必需的,因为枚举可能没有大小写,因此randomElement()
将返回nil
对于Swift 5,有“”:
enum工作日:caseitrable{
案件星期日、星期一、星期二、星期三、星期四、星期五、星期六
静态func随机(使用生成器:inout G)->工作日{
返回工作日.allCases.randomElement(使用:&生成器)!
}
静态func random()->工作日{
var g=SystemRandomNumberGenerator()
返回Weekday.random(使用:&g)
}
}
我使用answer编写了一个全局扩展。享受:)
最简单的方法是创建一个全局扩展:
extension CaseIterable {
static func randomElement() -> AllCases.Element {
guard Self.allCases.count > 0 else {
fatalError("There must be at least one case in the enum")
}
return Self.allCases.randomElement()!
}
}
这样,任何符合
caseitrable
的枚举都会自动执行该功能在这种情况下,您不需要指定特定的值;它们将从0
开始自动生成。仅当enum
没有基于整数的原始类型时,才引用文档中的部分。在同一文档的下一部分:“当整数用于原始值时,如果没有为某些枚举成员指定值,它们将自动递增。”@SebastianFlückiger您需要从arc4random
返回的原始值创建geometryclassion
:let shapeGeometry=geometryclassion(rawValue:(arc4random()%GeometryClassification.GeometryClassificationMax.rawValue))
@MikeS我不确定UInt32在这种情况下是否与“整数”相同。我假设是这样,但我认为,如果以这种方式使用枚举,则越具体越好。不过,我将编辑我的答案以反映这一点。@0O0O0它将自动生成带有UInt32
的值。这些值也应该是正确的如果要使用从arc4random
返回的值正常工作,请从0
开始(因为它当前仍在使用).@SebastianFlückiger查看我上面的编辑-这应该是让它工作所需的全部。如果您仍然有问题,请告诉我。您是对的-我最终采用了这种方法以使其更具可读性。感谢您的努力。++maxValue
将在Swift 3中被弃用。您将如何在代码中修复它?@Cesare:you c在循环中移动增量。谢谢。关于如何使此代码可重用,您有什么想法吗?我的应用程序中有三个枚举,我使用此代码三次。我考虑创建一个类(因为您不能用扩展扩展扩展枚举?)。这在Swift 1.2中不起作用。它需要为枚举分配一个rawValue。反过来,这意味着它只适用于具有Int rawValue类型的枚举。我的代码有一个输入错误,返回了错误的类型。上的小写字母和缺少括号。allCases很重要。我无意中使用了GeometryClassification.allCases().randomElement()!
(感谢您的自动完成),这是完全不同的,并导致运行时错误。对于Swift 5,这里有一个来自苹果的东西
extension CaseIterable {
static func random<G: RandomNumberGenerator>(using generator: inout G) -> Self.AllCases.Element {
return Self.allCases.randomElement(using: &generator)!
}
static func random() -> Self.AllCases.Element {
var g = SystemRandomNumberGenerator()
return Self.random(using: &g)
}
}
let state = YourEnum.random()
extension CaseIterable {
static func randomElement() -> AllCases.Element {
guard Self.allCases.count > 0 else {
fatalError("There must be at least one case in the enum")
}
return Self.allCases.randomElement()!
}
}