Swiftswift-问题栈Optional Swift编程珠玑

[Swift2.0系列]枚举中的递归

2015-09-19  本文已影响818人  NinthDay

Enumerations中的递归实现

1.基础语法

起初,Swift1.2想要支持枚举写法,我们通常需要自定义一个Box类用于封装需要传入的值,如下:

class Box<T>{
    let unbox:T
    init(_ value:T){self.unbox = value}
}

enum ArithmeticExpression<T>{
    case Number(T)
    case Addition(Box<ArithmeticExpression<T>>,Box<ArithmeticExpression<T>>)
    case Multiplication(Box<ArithmeticExpression<T>>,Box<ArithmeticExpression<T>>)
}

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

// 计算( 5 + 4) * 2表达式
let five = ArithmeticExpression.Number(5)
let four = ArithmeticExpression.Number(4)
let two = ArithmeticExpression.Number(2)
let sum = ArithmeticExpression.Addition(Box(five), Box(four))
let product = ArithmeticExpression.Multiplication(Box(sum), Box(two))
print(evaluate(product))//输出18

可以看到枚举中的关联值都是通过自定义类Box来封装的。正如对于表达式,无非就是数字(Number),4个运算符(+ - * /),需要传入左、右两个值进行计算。 虽说我们非常好的实现了枚举中的递归,但是问题显而易见,代码过于繁琐,不易理解。

幸运地是swift2.0语法中考虑到了这点,枚举支持递归写法,只需要在case之前写上关键字indirect即可,或者更省力的方式似乎在枚举声明头enum之前加上关键字indirect即可。现在来改写下上述代码:

indirect enum ArithmeticExpression {
    case Number(Int)
    case Addition(ArithmeticExpression, ArithmeticExpression)
    case Multiplication(ArithmeticExpression, ArithmeticExpression)
}

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

// evaluate (5 + 4) * 2
let five = ArithmeticExpression.Number(5)
let four = ArithmeticExpression.Number(4)
let sum = ArithmeticExpression.Addition(five, four)
let product = ArithmeticExpression.Multiplication(sum, ArithmeticExpression.Number(2))
print(evaluate(product))
// prints "18"

这种写法才是我们所期望的,简洁易懂。

2枚举知识的拓展

2.1Enumerations with Cases of Any Type

枚举的声明方式较为简单,如下:

enum 枚举名称:协议{
    case 匹配情况1
    case 匹配情况2(关联的值类型1)
    case 匹配情况3(关联的值类型,关联的值类型)
}

早前的swift中关联值可以是不同类型的,如下:

enum Number {
    case Integer(Int)
    case Real(Double)
}

Swift2.0加入了有趣的东西,这些关联了值的枚举case,可以当做函数来使用了!就像这样:

enum Number {
    case Integer(Int)
    case Real(Double)
}
let f = Number.Integer
// f是一个类型为(Int)->Number 的函数 即传入Int值 返回一个Number枚举类型

let evenInts:[Number] = [0,2,4,6].map(f)// 就能得到[.Integer(0),.Integer(2),.Integer(4),.Integer(6)]

2.2使用枚举递归声明节点树

enum Tree<T>{
    case Leaf
    indirect case Node(Tree,T,Tree)
}

其中case Node(Tree,T,Tree)节点中有三个元素,分别为左节点,节点值以及右节点。

2.3枚举中的raw-Value类型

一般枚举声明时带有raw-value的方式如下:

enum 枚举名称:raw-value类型,协议{
    case 枚举情况1 = raw value1
    case 枚举情况2 = raw value2
}

首先需要明确raw-value类型,或整数、浮点数、字符串当然也可以是单个字符,总之类型必须遵循了Equatable协议。以及以下literal-convertible协议中的一个:

举例来说:

enum Example:Int{
    case A,B,C = 5,C,D
}

可以看到结果值A=0,B=1,C=5,D=6

再来说说String类型,倘若我们明确了rawValue 类型为String,但是没有给case分配值,那默认为怎么样呢?

enum WeekendDay: String {
    case Saturday, Sunday
}

可以看到swift2.0String类型枚举默认值为自身名。其中WeekendDay.Saturday 就是"Saturday",WeekendDay.Sunday就是 "Sunday"

上一篇下一篇

猜你喜欢

热点阅读