一、枚举
下面是用枚举表示指南针四个方向的例子:
enum CompassPoint {
case North
case South
case East
case West
}
注意
与 C 和 Objective-C 不同,Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的CompassPoint例子中,North,South,East和West不会被隐式地赋值为0,1,2和3。相反,这些枚举成员本身就是完备的值,这些值的类型是已经明确定义好的CompassPoint类型。
directionToHead = .South
switch directionToHead {
case .North:
print("Lots of planets have a north")
case .South:
print("Watch out for penguins")
case .East:
print("Where the sun rises")
case .West:
print("Where the skies are blue")
}
正如在控制流(Control Flow)中介绍的那样,在判断一个枚举类型的值时,switch语句必须穷举所有情况。如果忽略了.West这种情况,上面那段代码将无法通过编译,因为它没有考虑到CompassPoint的全部成员。强制穷举确保了枚举成员不会被意外遗漏。
当不需要匹配每个枚举成员的时候,你可以提供一个default分支来涵盖所有未明确处理的枚举成员:
let somePlanet = Planet.Earth
switch somePlanet {
case .Earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
下面是三种特殊的枚举,涉及到关联值、原始值、递归枚举
1-1、关联值
enum TestAssociatedValueEnumerations{
case TestIntType(Int,Int)
case TestStringType(String)
}
var testOne = TestAssociatedValueEnumerations.TestIntType(10, 5)
testOne = .TestStringType("testString")
/*
关联值可以被提取出来作为 switch 语句的一部分。你可以在switch的 case 分支代码中提取每个关联值作为一个常量(用let前缀)或者作为一个变量(用var前缀)来使用
*/
switch testOne{
case .TestIntType(let numberOne, let numberTwo):
print("one===\(numberOne),two====\(numberTwo)")
case .TestStringType(let stringTest):
print("string ====\(stringTest)")
}
但是这样老有一个警告
switch condition evaluates to a constant
原因可能是因为编译器认为我的变量在函数内部一直是不变吧,于是就把变量从函数内部提出来,传人函数内部,写成下面这样,就可以编译通过没有任何的warning了.
// 当然在之前得调用下这个方法
testEnum(testOne)
// 具体的方法
func testEnum(testOne:TestAssociatedValueEnumerations){
// 为了更加简洁,也可以下面这样写(let 的合理用)
switch testOne{
case let .TestIntType(numberOne, numberTwo):
print("one===\(numberOne),two====\(numberTwo)")
case let .TestStringType(stringTest):
print("string ====\(stringTest)")
}
}
1-2、原始值
枚举成员可以被默认值(称为原始值)预填充,这些原始值的类型必须相同。
enum TestRawValueString: String {
case TestRawOne = "one"
case TestRawTwo = "Two"
case TestRawThree = "Three"
}
1-3、递归枚举
当各种可能的情况可以被穷举时,非常适合使用枚举进行数据建模,例如可以用枚举来表示用于简单整数运算的操作符。
可以在枚举类型开头加上indirect关键字来表明它的所有成员都是可递归的:
indirect enum ArithmeticExpression {
case Number(Int)
case Addition(ArithmeticExpression, ArithmeticExpression)
case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
//具体的计算
override func viewDidLoad() {
super.viewDidLoad()
// 计算 (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))
}
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)
}
}
二、类和结构体
类和结构体有着类似的定义方式。我们通过关键字class和struct来分别表示类和结构体,并在一对大括号中定义它们的具体内容:
class SomeClass {
// 类
}
struct SomeStructure {
// 结构体
}
具体例子
struct testStructFrame {
var x = 0
var y = 0
}
class testClassForStudent {
var name = "Lucy"
var age = 18
}
//所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中:
let myFrame = testStructFrame(x: 0, y: 0)
//类和结构体的实例
var ourStruct = testStructFrame()
let ourClass = testClassForStudent()
// 结构体 引用其属性,这样的话,
ourStruct.y = 100
ourStruct.x = 20
// 类 属性
ourClass.name = "Yang"
ourClass.age = 24
// 对比 ourStruct 是 var ,而ourClass 是 let
// 推断出 结构体是值类型,类是引用类型
// 值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。
// 与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝。因此,引用的是已存在的实例本身而不是其拷贝。
恒等运算符
因为类是引用类型,有可能有多个常量和变量在幕后同时引用同一个类实例。(对于结构体和枚举来说,这并不成立。因为它们作为值类型,在被赋予到常量、变量或者传递到函数时,其值总是会被拷贝。)
如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符:
等价于(===)
不等价于(!==)
注意 ==
和===
,也就是“等于”和“等价于”的区别
“等价于”表示两个类类型(class type)的常量或者变量引用同一个类实例。
“等于”表示两个实例的值“相等”或“相同”,判定时要遵照设计者定义的评判标准,因此相对于“相等”来说,这是一种更加合适的叫法。