枚举Enumerations ********************/

/*

枚举语法

使用Switch语句匹配枚举值

关联值

原始值

递归枚举

*/

// 枚举为一组相关的值定义了一个共同的类型,使你可以在你的代码中以类型安全的方式来使用这些值

// Swift中的枚举值更加灵活,不必给每一个枚举成员提供值.如果提供了(原始值),则该值的类型是字符串,字符或是一个整形值或浮点值

// 枚举成员可以指定任意类型的关联值存储到枚举成员中,就像其他语言中的联合体unions和变体variants.每一个枚举成员都可以有适当类型的关联值

// Swift中,枚举类型是一等(first-class)类型,他们采用了很多再传统上只做类所支持的特性.

// 计算机属性:用于提供枚举值的附加信息

// 实例方法:用于提供和枚举值相关联的功能

// 枚举也可以定义构造函数提供一个初始值,可以在原始实现的基础上扩展他们的功能,还可以遵循协议类提供标准的功能

// 枚举语法

使用enum关键字创建
enum
    //  枚举定义放在这
 }
 
// 指南针方向
enum
case
case
case
case
 }
.East

// case 关键字来定义一个新的枚举成员值

// 这些枚举值不会再直接赋予一个整形的0,1,2,3,这种值了,他们本身就是完备的值,这些值的类型是已经明确定义好的CompassPoint类型

// 多个成员值可以出现在同一行,用逗号隔开

enum
case
 }
var directionToHead =  CompassPoint.North

一旦directionToHead被声明为Planet类型,那么可以更简略

= .East

// 在使用具有显式类型的枚举值时,这种写法让代码具有更好的可读性

使用Switch语句匹配枚举值:

= .South
switch directionToHead{
case
    print("Lots of planets have a north")
case
    print("Watch out for penguins")
case
    print("Where the sun rises")
case
    print("Where the skies are blue")
 }

输出"Watch out for penguins"

// Switch语句必须穷举所有情况
 
let somePlanet = Planet.Earth
switch somePlanet{
case
    print("Mostly harmless")
:
    print("Not a safe place for humans")
 }

输出Mostly harmless

关联值

enum
case
case
 }

理解为:

定义一个名为Barcode的枚举类型,它的一个成员值是具有(Int,Int,Int,Int)类型关联值的UPCA,另一个成员值是具有String类型关联值的QRCode

这个定义不提供任何Int和 String类型的关联值,他只是定义了,当Barcode常量和变量等于Barcode.UPCA或Barcode.QRCode时,可以存储的关联值的类型

var productBarcode = Barcode.UPCA(8,85909, 51226,3)

创建一个productBarcode的变量,并将Barcode.UPCA赋值给它,关联的元组为(8, 85909, 51226, 3)

// 还可以给个不同类型的值

productBarcode = .QRCode("ABCDEFGHIJKLMNOP")

// Barcode类型的常量和变量可以存储一个.UPCA或者一个.QRCode(连同它们的关联值),但是在同一时间只能存储这两个值中的一个

switch productBarcode{
case .UPCA(let numberSystem,let manufacturer,let product,let
print("UPC-A:  \(numberSystem),  \(manufacturer),  \(product),  \(check).")
case .QRCode(let
print("QR code:\(productCode).")
 }

输出

// 如果一个枚举成员的所有关联值都被提取为变量,或者都被提取为变量,为了简洁,可以在成员名称前标注一个let或者var:

switch productBarcode{
case let
print("UPC-A:  \(numberSystem),  \(manufacturer),  \(product),  \(check).")
case let
print("QR code:\(productCode).")
 }

原始值

// 枚举成员可以被默认值(称为原始值)预填充,这些原始值的类型必须相同.

enum ASCIIControlCharcter:Character{
case Tab = "\t"
case UneFeed =  "\n"
case CarriageReturn =  "\r"
 }

// 原始值可以是字符串,字符,或者任意整型值或浮点型值.

// 原始值是在定义枚举时被预先填充的值,每个原始值在枚举声明中必须是唯一的.

// 关联值是创建一个基于枚举成员的常量或变量时才设置的值,枚举成员的关联值可以变化.

原始值的隐式赋值

// 在使用原始值为整数或者字符串类型的枚举时,不需要显式的为每一个枚举成员设置原始值,Swift将会自动赋值

// 如果使用整数为原始值时,隐式赋值的值依次递增1,如果第一个枚举值没有设置原始值,那么原始值默认为0

// 下面的枚举值是对之前Planet这个枚举值的一个细化,利用整型的原始值来表示每个行星在太阳系中的顺序

enum Planet1:Int
case Mercury =  1,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune
 }

// 当使用字符串作为枚举类型的原始值时,每个枚举成员的隐式原始值为该枚举成员的名称

// 下面的例子是CompassPoint枚举的细化,使用字符串类型的原始值来表达各个方向的名称

enum CompassPoint1:String{
case
 }

的隐式原始值South,依次类推

// 使用枚举成员的rawValue属性可以访问该枚举成员的原始值:
let earthsOrder =  Planet1.Earth.rawValue
print(earthsOrder)
 
let sunsetDirection =  CompassPoint1.West.rawValue

/* 如果这个枚举不写类型,是不是就意味着没有默认值,点不出来rawValue */

使用原始值初始化枚举实例

// 如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法

// 如果这个方法接收一个叫做rawValue的参数,参数类型为原始值类型,返回值为枚举成员或nil.

// 你可以使用这个初始化方法来创建一个新的枚举实例

// 这个例子利用原始值7创建了枚举成员Uranus:

let possiblePlanet1 = Planet1(rawValue: 7)

类型为Planet? 值为Planet.Uranus

// 注意:原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员

// 如:如果你试图寻找一个位置为9的行星,通过原始值构造器返回的可选Planet值将是nil

let positionToFind =  9
if let somePlanet1 =Planet1(rawValue: positionToFind)
 {
switch
case
        print("Mostly harmless")
    default:
        print("Not a safe place for humans")
     }
else
    print("There isn't a planet at position\(positionToFind)")
 }

这个例子使用了可选绑定(optional binding),

递归枚举

// 当各种可能的可以被穷举时,非常适合使用枚举进行数据建模.

// 例如可以用枚举来表示用于简单整数运算的操作符,这些操作符让你可以讲简单的算术表达式,例如整数5,结合为更为复杂的表达式,例如5+4

// 算术表达式的一个重要特性:表达式可以嵌套使用.例如(5+4)*2

// 乘号右边是一个数字,左边则是另一个表达式.

// 因为数据是嵌套的,因而用来存储数据的枚举类型也需要支持这种嵌套----这意味着枚举类型需要支持递归

// 递归枚举(Recursive enumerations)是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值.使用递归枚举时,编译器会插入一个间接层,你可以在枚举成员前加上indirect来表示该成员可递归.
enum
case
indirect case
indirect case
 }
// 也可以在枚举开头加上indirect(间接的,迂回的,非直接了当的)关键字来表明它的所有成员都是可递归的
indirect enum
case
case
case
 }
// 上面定义的枚举类型可以存储
 //ArithmeticExpression.Multiplication(ArithmeticExpression.Multiplication(<#T##ArithmeticExpression#>, <#T##ArithmeticExpression#>), <#T##ArithmeticExpression#>)

// 上面定义的枚举类型可以存储三种算术表达式:纯数字,两个表达式相加,两个表达式相乘.枚举成员Addition和Multiplication的关联值也是算术表达式---这些关联值使得嵌套表达式成为可能

// 要操作具有递归性质的数据结构,使用递归函数是一种直接了当的方式,

// 例如:下面是一个对算术表达式求值的函数

func evaluate(expression:ArithmeticExpression)->Int{
switch
case .Number(let
return
case .Addition(let left,let
return evaluate(left) +evaluate(right)
case .Multiplication(let left,let
return evaluate(left) *evaluate(right)
     }
 }

计算(5 + 4) * 2

let five =  ArithmeticExpression.Number(5)
let four =  ArithmeticExpression.Number(4)
let two = ArithmeticExpression.Number(2)
print(evaluate(two))
let sum = ArithmeticExpression.Addition(five,four)
let product =  ArithmeticExpression.Multiplication(sum,two)
print(evaluate(product))

// 该函数如果遇到纯数字,就直接返回该数字的值,如果遇到的是加法或者是乘法,就分别计算左右的值,然后进行计算