Swift中的枚举

在Swift中,我们具有一流的类型:类,结构,协议和枚举。 这样,我们就可以在拥有清晰可读的代码的同时创建令人惊奇的事物。

本文将为您介绍以下主题:何时使用枚举,其语法,枚举的类型,对其进行迭代,枚举的属性和方法,关联值以及比较枚举。 希望您是口袋妖怪迷。

何时使用枚举

如果需要对相关值进行分组,则可以使用枚举。 在下面的示例中,我们将创建一个Pokemon类并定义“ Type”。 (请注意,代码中的Type称为Kind)

 神奇宝贝课程 { 
/// Pokedex号
指数:整数

///宠物小精灵的名字
变量名称:字符串

初始化 (索引:整数,名称:字符串){...}
}

我们的Pokemon类是用pokedex编号 (索引)和name属性设置的。 我们要添加类型(火,草,水等)属性。

我们可能会考虑使用结构来定义类型。

 宠物小精灵扩展名 { 
struct Kind {
//类型名称
变量名称:字符串
}
}

但是我们对这种方法有疑问。
1.我们允许任何字符串成为神奇宝贝类型

2.比较变得复杂

   pokemonElectricType = Pokemon.Kind(name:“ Electric”) 
pokemonElectric2Type = Pokemon.Kind(name:“ Electric”)
  //这不起作用😬 
打印(pokemonElectricType == pokemonElectric2Type)
  //检查字符串var“ name”起作用 
打印(pokemonElectricType.name == pokemonElectric2Type.name)
  //这不可能 
nonsenseType = Pokemon.Kind(name:“无意义”)

我们当然可以使用这种方法,但是使用枚举会更干净。

句法

使用关键字enum ,然后使用案例进行定义。 对于口袋妖怪的类型,我们将为每种类型编写一个案例。

 宠物小精灵扩展名 { 
枚举种类{
外壳电,火,水,草
}
}

更好! 我们可以删除Type结构并使用我们的枚举。
我们不允许其他开发人员使用我们的代码创建随机的Pokemon类型。 另外,比较类型更容易,我们不比较字符串。

 神奇宝贝 { 
/// Pokedex号
指数:整数
///宠物小精灵的名字
变量名称:字符串
///口袋妖怪的类型
var type:类型

初始化 (索引:整数,名称:字符串,类型:类型){
自我 .index =索引
自我 .name =名称
自我 .type =类型
}
}
  let pikachu = Pokemon(索引:25,名称:“ Pikachu”,键入:.electric) 
  如果 pikachu.type == .electric { 
print(“ \(pikachu.name)是Electric”)
}

请注意,初始化Pokemon对象时不必编写Pokemon.Type.electric。

枚举RawValues

枚举可以具有定义的类型。 此类型与每种情况相关联,并用称为rawValue的属性表示

可以将符合RawRepresentable协议的对象定义为Enum类型。 我们可以使用与枚举类型关联的对象来初始化枚举。 如果对象不匹配,则为nil初始化。

Swift基础中的大多数对象都符合RawRepresentable:String,Int,Double等。如果将枚举定义为Int或String,则Swift会创建一个名为Implicitly Assigned的东西,并自动为每种情况添加rawValue。

  枚举类型:字符串{ 
外壳电,火,水,草
}
  print(Pokemon.Type.electric.rawValue)//打印电 
   electricTypeFromString = Pokemon.Kind.init(rawValue:“ electric”) 
nilTypeFromString = Pokemon.Kind.init(rawValue:“⚡️-雷声”)

枚举属性和方法

在Swift枚举中可以具有属性。 这些属性不能存储,但是可以计算。 它们使我们可以获取有关枚举电流值的更多信息。

  枚举类型:字符串{ 
外壳电,火,水,草
  ///一个大写的字符串 
变量名称:字符串{
返回 self .rawValue.capitalized
}
  ///带有表情符号的字符串将重置当前类型 
var emoji:字串{
切换 自我 {
案例 .electric:
返回 “⚡️”
案例 .fire:
返回 “🔥”
案例 .water:
返回 “💧”
案例 .grass:
返回 “🌱”
}
}
  ///相对于当前类型弱的类型的数组 
var优势:[种类] {
切换 自我 {
案例 .electric:
返回 [.fire,.water]
案例 .fire:
返回 [.grass]
案例 .water:
返回 [.fire]
案例 .grass:
返回 [.electric,.water]
}
}
  ///一个针对当前类型的类型数组 
var弱点:[种类] {...}
}
  let electricType =宠物小精灵 
let waterType =宠物小精灵.kind.water
如果 electricType.strengths.contains(waterType){
//⚡️ 类型又好 good
print(“ \(electricType.emoji)对\(waterType.emoji)有利)
}

Swift还允许我们向枚举添加方法。 这可以为特定的枚举案例提供更多功能。

  枚举类型:字符串{ 
外壳电,火,水,草
  ///一个大写的字符串 
var名称:字符串{...}
  ///带有表情符号的字符串将重置当前类型 
var emoji:字符串{...}
  ///相对于当前类型弱的类型的数组 
var优势:[种类] {...}
  ///一个针对当前类型的类型数组 
var弱点:[种类] {...}
  ///评估当前类型是否强,再确定口袋妖怪的类型 
///
///- 参数 pokemon:将被评估的Pokemon
///- 返回 :如果当前类型为强类型,则返回true
宠物小精灵,否则返回false
func isStrongAgainstPokemon( _ pokemon:Pokemon)->布尔{
返回 自身 .strengths.contains(pokemon.type)
}
}
  let waterType =宠物小精灵.kind.water 
let pikachu = Pokemon(索引:25,名称:“ Pikachu”,键入:.electric)
打印(waterType.isStrongAgainstPokemon(pikachu))

迭代枚举

如果我们想得到一个枚举的所有情况,可以用一种简单的方式做到。 枚举可以实现协议。 为了获得所有案例的数组,我们可以实现CaseIterable协议。

因此,要获取我们所有的Pokemon类型并对其进行迭代,我们可以执行以下操作:

  枚举类型:字符串,CaseIterable { 
外壳电,火,水,草
  ///一个大写的字符串 
var名称:字符串{...}
  ... 
}
  用于 Pokemon.Kind.allCases中的类型{ 
打印(type.name)
}

关联价值

使用Swift,可以将特定值存储到案例中。 此值称为关联属性。 这意味着一个案例可以具有与另一个案例不同的属性。

在我们的示例中,我们想要定义口袋妖怪的当前状态。 它可能是狂野的,也可能属于教练员。 如果它属于培训师,我们想知道是哪个培训师。 为了解决这个问题,我们可以使用带有2个case wild和Trainer的Enum 我们使用关联的值来将训练器对象匹配到我们的训练器案例。

 神奇宝贝 { 

指数:整数
变量名称:字符串
var类型:种类
  var status:状态= .wild 
  初始化 (索引:整数,名称:字符串,类型:类型){...} 
}
 培训师 { 
//培训者的名字
var id:字符串

//培训者的名字
变量名称:字符串

初始化 (ID:字符串,名称:字符串){
自我 .id = id
自我 .name =名称
}
}
 宠物小精灵扩展名 { 
枚举状态{
大小写
案例负责人(培训师:培训师)

var isWild:Bool {
切换 自我 {
案例 .wild:
返回
默认值
返回
}
}
}
}
   eduardoTrainer =培训师(id:“ T1”,名称:“ Eduardo”) 
let pikachu = Pokemon(索引:25,名称:“ Pikachu”,键入:.electric)
  pikachu.status = .owner(培训师:eduardoTrainer) 
  如果 pikachu.status.isWild { 
打印(“这个家伙很疯狂,抓住它!”)
} 其他 {
打印(“皮卡丘属于某人”)
}

并获得教练名称:

 神奇宝贝课程 { 

指数:整数
变量名称:字符串
var类型:种类
var status:状态= .wild
  var培训师:培训师?  { 
切换 self .status {
案例 .wild:
返回
案例 .owner( 培训师):
回程教练
}
}
  初始化 (索引:整数,名称:字符串,类型:类型){...} 
}
  ... 
 打印(pikachu.trainer?.name ??“没有所有者”) 

比较枚举

默认情况下,如果枚举具有rawValue,它将用于比较枚举。 这是因为RawRepresentable符合Equatable,Comparable和Hashable协议。

如果我们没有为枚举定义类型并且它具有关联的值,那么我们将无法进行比较。 这些枚举不符合Equatable协议。 不错的是,我们可以添加Equatable协议进行比较。 让我们看一下Pokemon.Status的示例。

  扩展名 Pokemon.Status:Equatable { 
  静态 函数 ==(lhs:Pokemon.Status,rhs:Pokemon.Status)-> Bool { 
如果 lhs.isWild && rhs.isWild {
返回
}
  lhsTrainer:培训师?  = { 
切换 lhs {
案例 .wild:
返回
案例 .owner( 培训师):
回程教练
}
}()
   rhsTrainer:培训师?  = { 
切换 rhs {
案例 .wild:
返回
案例 .owner( 培训师):
回程教练
}
}()
  返回 lhsTrainer == rhsTrainer 
}
}
  扩展培训师:平等{ 
静态 函数 ==(lhs:培训师,rhs:培训师)->布尔{
返回 lhs.id == rhs.id
}
}
   eduardoTrainer =培训师(id:“ T1”,名称:“ Eduardo”) 
let pikachu = Pokemon(索引:25,名称:“ Pikachu”,键入:.electric)
let bulbasaur = Pokemon(索引:1,名称:“ Bulbasaur”,键入:.grass)
  pikachu.status = .owner(培训师:eduardoTrainer) 
bulbasaur.status = .owner(培训师:eduardoTrainer)
  如果 pikachu.status == bulbasaur.status { 
打印(“皮卡丘和Bulbasaur的状态相同”)
}

结论

(/ ^▽^)/

你做到了! (或者也许您只是向下滚动以查看评论)。 枚举在Swift中是必不可少的,我鼓励尝试使用它们,并在您的代码中使用它们。

请让我知道您在评论中的想法。

完整的游乐场:https://gist.github.com/eduardo22i/6ca76f8e044ba62eae7f0b356426abc5

苹果的Enum指南:https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html