[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
协议中的一个:
- IntegerLiteralConvertible(整数)
- FloatingPointLiteralConvertible(浮点数)
- StringLiteralConvertible(字符串)
- ExtendedGraphemeClusterLiteralConvertible
举例来说:
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.0
为String
类型枚举默认值为自身名。其中WeekendDay.Saturday 就是"Saturday",WeekendDay.Sunday就是 "Sunday"