★ 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 关键字。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容