Swift小结
不同的字符可能会占用不同数量的内存空间,所以要知道Character的确定位置,就必须从String开头遍历每一个 Unicode 标量直到结尾。因此,Swift 的字符串不能用整数(integer)做索引。
如果两个字符串(或者两个字符)的可扩展的字形群集是标准相等的,那就认为它们是相等的。在这个情况 下,即使可扩展的字形群集是有不同的 Unicode 标量构成的,只要它们有同样的语言意义和外观,就认为它们标 准相等。
var oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted() // 取并集
oddDigits.subtract(singleDigitPrimeNumbers) // 剔除交集
evenDigits.symmetricDifference(singleDigitPrimeNumbers).sorted() // 交集取反
图片.png
必须将延迟存储属性声明成变量(使用var关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
当值类型(枚举、结构体)的实例被声明为常量的时候,它的所有属性也就成了常量。属于引用类型的类(class)则不一样。把一个引用类型的实例赋给一个常量后,仍然可以修改该实例的变量属性。
必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。
跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过程中使用构造器给类型属性赋值。存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用lazy修饰符。
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func cal(isAdd: Bool) -> (Int) -> Int {
if isAdd {
return stepForward
}
return stepBackward
}
// 等价于
func caculate(isAdd: Bool) -> (Int) -> Int {
if isAdd {
func stepFor(input: Int) -> Int {
return input + 1
}
return stepFor
} else {
func stepBack(input: Int) -> Int {
return input - 1
}
return stepBack
}
}
// 调用1
cal(isAdd: true)(1)
// 调用2
caculate(isAdd: true)(1)
类型属性语法
在 C 或 Objective-C 中,与某个类型关联的静态常量和静态变量,是作为全局(global)静态变量定义的。但 是在 Swift 中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支 持的范围内。
使用关键字 static 来定义类型属性。在为类定义计算型类型属性时,可以改用关键字 class 来支持子类对父 类的实现进行重写。
例如:
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
获取和设置类型属性的值
跟实例属性一样,类型属性也是通过点运算符来访问。但是,类型属性是通过类型本身来访问,而不是通过实
例。
例如:
print(SomeStructure.storedTypeProperty) // 打印 "Some value."
SomeStructure.storedTypeProperty = "Another value." print(SomeStructure.storedTypeProperty) // 打印 "Another value.”
print(SomeEnumeration.computedTypeProperty) // 打印 "6"
print(SomeClass.computedTypeProperty) // 打印 "27"
在实例方法中修改值类型
结构体和枚举是值类型。默认情况下,值类型的属性不能在它的实例方法中被修改。
但是,如果你确实需要在某个特定的方法中修改结构体或者枚举的属性,你可以为这个方法选择 可变(mutatin g) 行为,然后就可以从其方法内部改变它的属性;并且这个方法做的任何改变都会在方法执行结束时写回到原始 结构中。方法还可以给它隐含的 self 属性赋予一个全新的实例,这个新实例在方法结束时会替换现存实例。
例如:如果没有mutating
,将报错Left side of mutating operator isn't mutable: 'self' is immutable
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
枚举的可变方法可以把
self
设置为同一枚举类型中不同的成员:
例如:
enum TriStateSwitch {
case Off, Low, High
mutating func next() {
switch self {
case .Off:
self = .Low
case .Low:
self = .High
case .High:
self = .Off
}
}
}
var ovenLight = TriStateSwitch.Low
ovenLight.next() // ovenLight 现在等于 .High
ovenLight.next() // ovenLight 现在等于 .Off
类型方法
实例方法是被某个类型的实例调用的方法。你也可以定义在类型本身上调用的方法,这种方法就叫做类型方 法。在方法的 func 关键字之前加上关键字 static ,来指定类型方法。类还可以用关键字 class 来允许子类重写 父类的方法实现。
注意
在 Objective-C 中,你只能为 Objective-C 的类类型(classes)定义类型方法(type-level methods)。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法。每一个类型方法都被它所支持的类型显式包含。
重写属性
你可以重写继承来的实例属性或类型属性,提供自己定制的 getter 和 setter,或添加属性观察器使重写的属性 可以观察属性值什么时候发生改变。
重写属性的 Getters 和 Setters
你可以提供定制的 getter(或 setter)来重写任意继承来的属性,无论继承来的属性是存储型的还是计算型的 属性。子类并不知道继承来的属性是存储型的还是计算型的,它只知道继承来的属性会有一个名字和类型。你在 重写一个属性时,必需将它的名字和类型都写出来。这样才能使编译器去检查你重写的属性是与超类中同名同类 型的属性相匹配的。
你可以将一个继承来的只读属性重写为一个读写属性,只需要在重写版本的属性里提供 getter 和 setter 即 可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。注意
如果你在重写属性中提供了 setter,那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改 继承来的属性值,你可以直接通过 super.someProperty 来返回继承来的值,其中 someProperty 是你要重写的属 性的名字。