★ iOS高级:Swift入门精讲③ 01 swift编程-03-枚举-02原始值_递归

前言

仅为视频学习笔记

原始值 (Raw Values)

★ 枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做:原始值

例子-1

 enum PokerSuit : Character {
     case spade = "♠️"
     case heart = "♥️"
     case diamond = "♦️"
     case club = "♣️"
 }

我以上面代码为例,我们会发现如下面这句代码PokerSuit和Character中间有一个冒号

 enum PokerSuit : Character

注意,这里的冒号并不代表什么继承之类的。不要一想到冒号就是遵守协议什么的,不是这个意思。

这个冒号用在枚举里面,你就认为它是一个原始值类型,不存在什么继承的概念,不要搞混。

一旦,我们写上 :Character,就意味着这个枚举,到时候它的成员所关联的的值是什么呢?就是它的默认值、原始值是什么呢?就是Character类型的。

你看,下面这句

 case spade = "♠️"

它关联的原始值是什么呢?就是♠️符号,如这个PokerSuit枚举中case 值依次对应的原始值为♠️、♥️、♦️、♣️。其实,这些是什么鬼呢?是扑克牌的花色。

我们会发现,四种枚举成员,都用同一种类型(Character),跟它预先关联了。


我们看一下怎么用

 var suit  = PokerSuit.spade
 print(suit) // spade
 print(suit.rawValue) // ♠️
 print(PokerSuit.club.rawValue) //♣️

我们假设定义一个 suit变量直接PokerSuit.spade,意思是把第一个成员赋值给了变量suit,到时候我们打印出来就是// spade。

由于呢,我们每一个枚举成员,都有自己的一个原始值,例如:case spade = "♠️",是等于号后面的♠️。所以说,你这个变量如果当初存储的是spade的话,那么你就能通过rawValue这个属性访问的话,相当于你访问的就是spade这个家伙的原始值。因为你这个suit枚举变量存储的成员是spade,所以它的原始值(rawValue)就是♠️。即 print(suit.rawValue)打印出来就是 // ♠️这个家伙。

当然, PokerSuit枚举中每一个枚举成员都有一个原始值所以我可以PokerSuit.club.rawValue,也就是说,我们可以直接拿到club这个成员,它的原始值其实就是♣️这个梅花。所以 print(PokerSuit.club.rawValue) 打印出来就是这个♣️梅花

例子-2

 enum Grade : String {
     case perfect = "A"
     case great = "B"
     case good = "C"
     case bad = "D"
 }
 
 print(Grade.perfect.rawValue) // A
 print(Grade.great.rawValue)   // B
 print(Grade.good.rawValue)    // C
 print(Grade.bad.rawValue)     // D

我们看上面这段,代码。我们等级定义了四种,分别为 perfect、great、good、bad。然后呢,我们在Grade后面写了一个冒号加字符串( : String),意思就是枚举内的成员,到时候关联的原始值就是String,分别为A、B、C、D。

根据上面的print输出,我们可以看出,通过 (Grade.perfect.rawValue)打印出成员的原始值。其实,打印出来的就是A、B、C、D。

隐式原始值 (Implicitly Assigned Raw Values)

★ 如果枚举的原始值类型是Int、String,Swift会自动分配原始值

例子-1

 enum Direction : String {
     case north = "north"
     case south = "south"
     case east  = "east"
     case west  = "west"
 }

我们看上面这个例子,方向,就是东、南、西、北四个方向,由于呢,我们上面** : String**这样写的,就意味着到时候枚举内部所预先关联的原始值是字符串类型。其实,上面这种写法等价于下面这种写法:

 enum Direction : String {
     case north, south , east, west
 }
 
 print(Direction.north) // north
 print(Direction.north.rawValue) // north

也就是,说上面两段代码,完全等价,因为我们刚才说了,如果你的原始值类型是String的话,这个swift其实会自动分配north, south , east, west这几个成员的原始值。

那么,怎么个分配法呢?就是你的成员的名字叫什么,那么到时候给你预先关联的原始值就是什么 如下面,这两段代码的输出,一个打印成员,一个是打印成员的默认值,都为north。

 print(Direction.north) // north
 print(Direction.north.rawValue) // north

例子- 2

  enum Season : Int {
      case spring, summer, autumn, winer
  }
  
  print(Season.spring.rawValue) // 0
  print(Season.summer.rawValue) // 1
  print(Season.autumn.rawValue) // 2
  print(Season.winer.rawValue)  // 3        

如果你枚举类型是Int类型,其实也是一样的。它会自动分配这个原始值。那么,如果是Int,它怎么分配呢?

如spring这个家伙,它默认会关联一个 0,summer关联一个 1,关联一个 2,关联一个 3,即按顺序 0,1,2,3。

所以,我们打印出来的Season内部成员的原始值依次为: 0,1,2,3。

例子- 3

  enum Season : Int {
      case spring = 1, summer, autumn = 4, winer
  }
  
  print(Season.spring.rawValue) // 1
  print(Season.summer.rawValue) // 2
  print(Season.autumn.rawValue) // 4
  print(Season.winer.rawValue)  // 3

如上代码,如果你指定了spring的原始值为1的话,那么下一个就会递增,也就是说summer的原始值为2。如果autumn的原始值为4的话,那么下一个winer的原始值就为5。所以这几个家伙按顺序打印出来就是 // 1,2,4,5

枚举递归 (Recursive Enumeration)

 indirect enum ArithExpr {
    case number(Int)
    case sum(ArithExpr,ArithExpr)
    case difference(ArithExpr,ArithExpr)
}

什么叫做枚举递归呢?你看一下,我们现在定一个一个枚举类型,发现了吗?这个枚举变量的成员里面,它的关联值,也用到了ArithExpr枚举类型。也就是说,这个枚举成员里面也用到了这个枚举,这个叫做递归枚举。也就是你自己用到了你自己的类型。

那么递归枚举要定义成功的话,你得在枚举前面加上indirect这个关键字。如果你不加编译器会报错的,编译器会直接提醒你,你这个递归枚举必须得加这个关键字。


或者,还可以下面这样写:

  enum ArithExpr {
     case number(Int)
     indirect  case sum(ArithExpr,ArithExpr)
     indirect  case difference(ArithExpr,ArithExpr)
 }

如上,只有

     indirect  case sum(ArithExpr,ArithExpr)
     indirect  case difference(ArithExpr,ArithExpr)    

这两个case 才用到了递归,也就是自己用自己,所以你完全可以如上,在这两个家伙前面加上indirect,也是可以的,但是一般简单的方式就是第一种,直接在最前面加上indirect就可以了。

那么,我么看一下这个枚举表达什么含义呢?ArithExpr你可以理解为算数表达式的简称。算数表达式的话,我们现在分为两种,一种是sum加法,一种是difference减法。那么加法的话 sum(ArithExpr,ArithExpr),你依然要传两个算数表达式给我,减法也是一样。

然后呢,算数表达式的一部分,还有一个情况是什么呢?这种情况,其实就是数值 number。

你思考一下,平常我们学的算数表达式,不是这样的吗?

 1 + 2

那么,这个算数表达式它由什么组成,有具体的数值,也就是操作数,还有你具体想要做什么运算(+) ,是由这些东西组成的。

所以,我们看一下,我们定义的算数表达式,不就是这样的吗?

首先,一种情况,你可能是一个数字case number(Int),或者说你可能是一个具体的运算 indirect case sum(ArithExpr,ArithExpr)。

那我们看一下,那么,我们要定义一则运算的话,可以下面这样定义:

 let five = ArithExpr.number(5)
 let four = ArithExpr.number(4)
 let two  = ArithExpr.number(2)
 let sum  = ArithExpr.sum(five, four)
 let difference = ArithExpr.difference(sum, two)

我们看第一个

 let five = ArithExpr.number(5)

ArithExpr.number(5)相当于 five这个枚举变量其实是 case number(Int)这个成员。第二句和第三句如同。都是属于 case number(Int)这个成员。

接下来,再来一个sum,sum它是由于要接收两个枚举类型,那你想想,当定义的five和four,这两个不是刚好就是枚举类型吗?所以这个five和four是可以传给sum的将它们关联起来,所以这个 let sum = ArithExpr.sum(five, four),sum关联了five和four。那么,到时候你思考一下,那么它的语义,想表达的就是5+4吗? 所以,sum,其实代表的就是5+4

然后,最后一个呢? let difference = ArithExpr.difference(sum, two)。这个算数表达式difference,它是接收两个枚举类型,那么很明显这个sum和这个two,这两个家伙就是ArithExpr这个枚举类型的,那么我们可以猜想的到我们difference这个枚举变量,想表达的是什么?首先你这个sum执行的就是5+4。那么5+4又要减 2,应该是这样的一个意思。

那么最终,我们是想根据difference表达式的语义,算出最终的值,怎么办呢?这个时候,我们可以写一个函数,如下:

  func calculate(_ expr: ArithExpr) -> Int {
      switch expr {
      case let .number(value):
          return value
      case let .sum(left, right):
          return calculate(left) + calculate(right)
      case let .difference(left, right):
          return calculate(left) - calculate(right)
    }
  }
  
  calculate(difference)

你传一个表达式给calculate,它来给你算,里面有一个switch,就不说了。所以呢,到时候,就把这个difference变量传进去,就进行详细的判断,根据你是哪一个case进行相应的判断。比如说,你是sum 那就作加法,difference就作减法,如果你number就返回具体的数值。

★ 本质是想说明,枚举类型中case用到它本身的话,这个递归枚举必须得加一个indirect 关键字。

你可能感兴趣的:(★ iOS高级:Swift入门精讲③ 01 swift编程-03-枚举-02原始值_递归)