From: AceVest Date: Sun, 26 Mar 2017 08:20:27 +0000 (+0800) Subject: Swift - Generics AddvancedOperators X-Git-Url: http://zhaoyanbai.com/repos/icons/jhe061.png?a=commitdiff_plain;h=cdf564fb08e27b33717ca36762661c6e124a4102;p=acecode.git Swift - Generics AddvancedOperators --- diff --git a/learn/AcePlay/AcePlay.playground/Pages/ARC.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/ARC.xcplaygroundpage/Contents.swift index 5f157bb..07847a7 100644 --- a/learn/AcePlay/AcePlay.playground/Pages/ARC.xcplaygroundpage/Contents.swift +++ b/learn/AcePlay/AcePlay.playground/Pages/ARC.xcplaygroundpage/Contents.swift @@ -131,12 +131,12 @@ unit7C!.tenant = bill print("----------destroy bill------------") // PersonWeak实例依然保持对ApartmentWeak实例的强引用 // 但是ApartmentWeak实例现在对PersonWeak实例是弱引用 -// 这意味着当你断开bill变量所保持的强引用时,再也没有指向PersonWeak实例的强引用了,由于再也没有指向PersonWeak实例的强引用,该实例会被释放 +// 这意味着当断开bill变量所保持的强引用时,再也没有指向PersonWeak实例的强引用了,由于再也没有指向PersonWeak实例的强引用,该实例会被释放 bill = nil print("----------destroy unit7C------------") -// 现在只剩下来自unit7C变量对ApartmentWeak实例的强引用。如果你打断这个强引用,那么ApartmentWeak实例就再也没有强引用了 +// 现在只剩下来自unit7C变量对ApartmentWeak实例的强引用。如果打断这个强引用,那么ApartmentWeak实例就再也没有强引用了 unit7C = nil @@ -178,7 +178,7 @@ carl = Customer(name: "Carl") carl!.card = CreditCard(number: 314_1414_1732, customer: carl!) // 现在Customer实例对CreditCard实例有一个强引用,并且CreditCard实例对Customer实例有一个无主引用 -// 由于 Customer 的无主引用,当你断开 john 变量持有的强引用时,那么就再也没有指向 Customer 实例的强引用了 +// 由于 Customer 的无主引用,当断开 john 变量持有的强引用时,那么就再也没有指向 Customer 实例的强引用了 // 因为不再有 Customer 的强引用,该实例被释放了。其后,再也没有指向 CreditCard 实例的强引用,该实例也随之被释放了 print("----------destroy carl------------") carl = nil @@ -267,7 +267,7 @@ paragraph = nil // Swift通过闭包捕获列表来解决这个问题 -// Swift要求你在闭包中引用self成员时使用self.someProperty或者self.someMethod 而不只是 someProperty或someMethod)。这有助于提醒你可能会一不小心就捕获了self +// Swift要求在闭包中引用self成员时使用self.someProperty或者self.someMethod 而不只是 someProperty或someMethod)。这有助于提醒可能会一不小心就捕获了self // 捕获列表中的每一项都由 weak 或 unowned 关键字与类实例的引用(如 self )或初始化过的变量(如 delegate = self.delegate! )成对组成。这些项写在方括号中用逗号分开。 // 把捕获列表放在形式参数和返回类型前边,如果它们存在的话 @@ -320,4 +320,4 @@ print("----------destroy paragraph2------------") var paragraph2: HTMLElementV2? = HTMLElementV2(name: "p", text: "hello ARC") paragraph2 = nil -print("begin deinit") \ No newline at end of file +print("begin deinit") diff --git a/learn/AcePlay/AcePlay.playground/Pages/AdvancedOperators.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/AdvancedOperators.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..263016e --- /dev/null +++ b/learn/AcePlay/AcePlay.playground/Pages/AdvancedOperators.xcplaygroundpage/Contents.swift @@ -0,0 +1,53 @@ +//: [Previous](@previous) + +import Foundation + +var str = "Hello, Advanced Operators" + +//: [Next](@next) + + +// 自定义运算符 +// 除了实现标准运算符,在 Swift 中还可以声明和实现自定义运算符 +// 要指定 prefix、infix 或者 postfix 前缀 中缀 后缀 + +struct Vector2D { + var x = 0.0 + var y = 0.0 +} + + +prefix operator +++ +infix operator +-: AdditionPrecedence // 此运算符属于 AdditionPrecedence 优先组 + +extension Vector2D { + + static func + (left: inout Vector2D, right: Vector2D) -> Vector2D { + return Vector2D(x: left.x+right.x, y: left.y+right.y) + } + + static func += (left: inout Vector2D, right: Vector2D) { + left = left + right + } + + + static prefix func +++ (vector: inout Vector2D) -> Vector2D { + vector += vector + return vector + } + + static func +- (left: Vector2D, right: Vector2D) -> Vector2D { + return Vector2D(x: left.x + right.x, y: left.x - right.y) + } +} + + +var va = Vector2D(x: 1.0, y: 2.0) +print(+++va) + +let firstVector = Vector2D(x: 2.0, y: 3.0) +let secondVector = Vector2D(x: 3.0, y: 4.0) +print(firstVector +- secondVector) + + + diff --git a/learn/AcePlay/AcePlay.playground/Pages/Extensions.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/Extensions.xcplaygroundpage/Contents.swift index 4e753f7..1c6abd5 100644 --- a/learn/AcePlay/AcePlay.playground/Pages/Extensions.xcplaygroundpage/Contents.swift +++ b/learn/AcePlay/AcePlay.playground/Pages/Extensions.xcplaygroundpage/Contents.swift @@ -18,7 +18,7 @@ var str = "Hello, Extensions" // 6. 使一个已有类型符合某个协议 -// 在 Swift 中,你甚至可以对协议进行扩展,提供协议要求的实现,或者添加额外的功能,从而可以让符合协议的类型拥有这些功能 +// 在 Swift 中,甚至可以对协议进行扩展,提供协议要求的实现,或者添加额外的功能,从而可以让符合协议的类型拥有这些功能 // 注意:扩展可以为一个类型添加新的功能,但是不能重写已有的功能。 // 语法 @@ -34,7 +34,7 @@ var str = "Hello, Extensions" // // 协议实现写到这里 //} -// 注意: 如果你通过扩展为一个已有类型添加新功能,那么新功能对该类型的所有已有实例都是可用的,即使它们是在这个扩展定义之前创建的 +// 注意: 如果通过扩展为一个已有类型添加新功能,那么新功能对该类型的所有已有实例都是可用的,即使它们是在这个扩展定义之前创建的 @@ -185,4 +185,4 @@ func printIntegerKinds(_ numbers: [Int]) { var numbers: [Int] = [1, 2, 3, -1, 0, -8] -printIntegerKinds(numbers) \ No newline at end of file +printIntegerKinds(numbers) diff --git a/learn/AcePlay/AcePlay.playground/Pages/Generics.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/Generics.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..44b508d --- /dev/null +++ b/learn/AcePlay/AcePlay.playground/Pages/Generics.xcplaygroundpage/Contents.swift @@ -0,0 +1,176 @@ +//: [Previous](@previous) + +import Foundation + +var str = "Hello, Generics" + +//: [Next](@next) + +func swapTwoValues(_ a: inout T, _ b: inout T) { + var c: T + c = a + a = b + b = c +} + +var aInt = 3 +var bInt = 4 + +swapTwoValues(&aInt, &bInt) +print(aInt, bInt) + + +var aStr = "aStr" +var bStr = "bStr" +swapTwoValues(&aStr, &bStr) +print(aStr, bStr) + + +// 可提供多个类型参数,将它们都写在尖括号中,用逗号分开 +// 如Dictionary 中的 Key 和 Value + + +class Stack { + var stack = [Element]() + + func push(_ item: Element) { + stack.append(item) + } + + func pop() -> Element? { + return stack.removeLast() + } + + var size: Int { + return stack.count + } +} + +var stackOfStrings = Stack() +stackOfStrings.push("A") +stackOfStrings.push("B") +stackOfStrings.push("C") +stackOfStrings.push("DEFG") + +while stackOfStrings.size > 0 { + var s = stackOfStrings.pop() + print(s!) +} + + + +// 类型约束 +// 可以在一个类型参数名后面放置一个类名或者协议名,并用冒号进行分隔,来定义类型约束 +// 这个函数有两个类型参数。第一个类型参数 T,有一个要求 T 必须是 SomeClass 子类的类型约束;第二个类型参数 U,有一个要求 U 必须符合 SomeProtocol 协议的类型约束 +//func someConstraintGenericFunc(someT: T, someU: U) { +// +//} + + +// Swift 标准库中定义了一个 Equatable 协议,该协议要求任何遵循该协议的类型必须实现等式符(==)及不等符(!=),从而能对该类型的任意两个值进行比较 +func findIndex(of valueToFind: T, in array: [T]) -> Int? { + for (index, value) in array.enumerated() { + if value == valueToFind { // 需要T类型支持Equatable的协议 + return index + } + } + + return nil +} + +print(findIndex(of: 1.2, in: [1.3, 4.0, 5, 8.9]) ?? "can not find 1.2") +print(findIndex(of: "ace", in: ["john", "obama", "ace"]) ?? "nothing") + + + + +// 关联类型 +// 定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分将会非常有用。 +// 关联类型为协议中的某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定。 +// 可以通过 associatedtype 关键字来指定关联类型。 + +protocol Container { + associatedtype T + mutating func append(_ item: T) + var count: Int { get } + subscript(i: Int) -> T { get } +} + + +struct StackB: Container { + var stack = [Element]() + + mutating func push(_ item: Element) { + stack.append(item) + } + + mutating func pop() -> Element? { + return stack.removeLast() + } + + var size: Int { + return stack.count + } + + mutating func append(_ item: Element) { + self.push(item) + } + + var count: Int { + return size + } + + subscript(i: Int) -> Element { + return stack[i] + } +} + + + +// +// 通过扩展一个存在的类型来指定关联类型 +// +// 通过扩展添加协议一致性中描述了如何利用扩展让一个已存在的类型符合一个协议,这包括使用了关联类型的协议。 +// +// Swift 的 Array 类型已经提供 append(_:) 方法,一个 count 属性,以及一个接受 Int 类型索引值的下标用以检索其元素。 +// 这三个功能都符合 Container 协议的要求,也就意味着只需简单地声明 Array 采纳该协议就可以扩展 Array,使其遵从 Container 协议。可以通过一个空扩展来实现这点,正如通过扩展采纳协议中的描述: +// +extension Array: Container {} +// 如同上面的泛型 Stack 结构体一样,Array 的 append(_:) 方法和下标确保了 Swift 可以推断出 ItemType 的类型。定义了这个扩展后,可以将任意 Array 当作 Container 来使用。 + + + +// 泛型 Where 语句 +// C1 必须符合 Container 协议(写作 C1: Container)。 +//C2 必须符合 Container 协议(写作 C2: Container)。 +//C1 的T必须和C2的T类型相同(写作 C1.T == C2.T)。 +//C1 的T必须符合Equatable 协议(写作 C1.T: Equatable) +func allItemsMatch(_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.T == C2.T, C1.T: Equatable { + if someContainer.count != anotherContainer.count { + return false + } + + for i in 0..() +stringStack.push("abc") +stringStack.push("def") +stringStack.push("xyz") + +var stringArray = ["abc", "def", "xyz"] + +if allItemsMatch(stringStack, stringArray) { + print("All items match") +} else { + print("Not all items match") +} + + diff --git a/learn/AcePlay/AcePlay.playground/Pages/Inheritance.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/Inheritance.xcplaygroundpage/Contents.swift index dc1cf1d..da680b4 100644 --- a/learn/AcePlay/AcePlay.playground/Pages/Inheritance.xcplaygroundpage/Contents.swift +++ b/learn/AcePlay/AcePlay.playground/Pages/Inheritance.xcplaygroundpage/Contents.swift @@ -41,7 +41,7 @@ print("Tandem: \(someTandem.description)") // 重写 // 子类可以为继承来的实例方法,类方法,实例属性,或下标提供自己定制的实现。我们把这种行为叫重写 -// 如果要重写某个特性,你需要在重写定义的前面加上override关键字 +// 如果要重写某个特性,需要在重写定义的前面加上override关键字 class Train: Vehicle { override func makeNoise() { print("Choo Choo") @@ -57,7 +57,7 @@ someTrain.makeNoise() // 可以将一个继承来的只读属性重写为一个读写属性 // 不可以将一个继承来的读写属性重写为一个只读属性 -// 如果在重写属性中提供了setter,那么你也一定要提供getter +// 如果在重写属性中提供了setter,那么也一定要提供getter // 如果不想在重写版本中的getter 里修改继承来的属性值 // 可以直接通过super.someProperty来返回继承来的值,其中someProperty是要重写的属性的名字 diff --git a/learn/AcePlay/AcePlay.playground/Pages/Initialization.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/Initialization.xcplaygroundpage/Contents.swift index a9c2686..67ed19b 100644 --- a/learn/AcePlay/AcePlay.playground/Pages/Initialization.xcplaygroundpage/Contents.swift +++ b/learn/AcePlay/AcePlay.playground/Pages/Initialization.xcplaygroundpage/Contents.swift @@ -49,7 +49,7 @@ let freezingPointOfWather = Celsius(fromKelvin: 273.15) // 构造器并不像函数和方法那样在括号前有一个可辨别的名字 // 因此在调用构造器时,主要通过构造器中的参数名和类型来确定应该被调用的构造器 -// 正因为参数如此重要,如果你在定义构造器时没有提供参数的外部名字,Swift会为构造器的每个参数自动生成一个跟内部名字相同的外部名 +// 正因为参数如此重要,如果在定义构造器时没有提供参数的外部名字,Swift会为构造器的每个参数自动生成一个跟内部名字相同的外部名 struct Color { var red, green, blue: Double @@ -71,8 +71,8 @@ let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) let halfGray = Color(white: 0.5) -// 如果不通过外部参数名字传值,你是没法调用这个构造器的 -// 只要构造器定义了某个外部参数名,你就必须使用它,忽略它将导致编译错误 +// 如果不通过外部参数名字传值,是没法调用这个构造器的 +// 只要构造器定义了某个外部参数名,就必须使用它,忽略它将导致编译错误 // let green = Color(0.0, 1.0, 0.0) 这段代码会报编译时错误,需要外部名称 let bodyTemperature = Celsius(37.2) @@ -132,7 +132,7 @@ let size1 = Size(width: 2.3, height: 3.7) // 逐一构造器 // 值类型(结构体和枚举类型)的构造器代理不支持继承,所以构造器代理的过程相对简单 // 对于值类型,可以使用self.init在自定义的构造器中引用相同类型中的其它构造器。并且只能在构造器内部调用self.init // 如果为某个值类型定义了一个自定义的构造器,将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器) -// 如果希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例 +// 如果希望默认构造器、逐一成员构造器以及自己的自定义构造器都能用来创建实例 // 可以将自定义的构造器写到扩展(extension)中,而不是写在值类型的原始定义中 struct Point { @@ -266,7 +266,7 @@ print("SomeBicycel: \(someBicycle.description)") // 规则1: 如果子类没有定义任何`指定构造器`,它将自动继承所有父类的指定构造器。 // 规则2: 如果子类提供了所有父类指定构造器的实现——无论是通过规则1继承过来的,还是提供了自定义实现——它将自动继承所有父类的`便利构造器` // 注意: -// 1. 即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。 +// 1. 即使在子类中添加了更多的便利构造器,这两条规则仍然适用。 // 2. 对于规则2,子类可以将父类的指定构造器实现为便利构造器。 diff --git a/learn/AcePlay/AcePlay.playground/Pages/OptionalChaining.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/OptionalChaining.xcplaygroundpage/Contents.swift index 0705036..89cfe4e 100644 --- a/learn/AcePlay/AcePlay.playground/Pages/OptionalChaining.xcplaygroundpage/Contents.swift +++ b/learn/AcePlay/AcePlay.playground/Pages/OptionalChaining.xcplaygroundpage/Contents.swift @@ -180,8 +180,8 @@ print(scores.description) // 连接多层可选链式调用 // 可以通过连接多个可选链式调用在更深的模型层级中访问属性、方法以及下标。然而,多层可选链式调用不会增加返回值的可选层级。 // 也就是说 -// 1. 如果你访问的值不是可选的,可选链式调用将会返回可选值 -// 2. 如果你访问的值就是可选的,可选链式调用不会让可选返回值变得“更可选” +// 1. 如果访问的值不是可选的,可选链式调用将会返回可选值 +// 2. 如果访问的值就是可选的,可选链式调用不会让可选返回值变得“更可选” // 因此 // 通过可选链式调用访问一个Int值,将会返回Int?,无论使用了多少层可选链式调用 diff --git a/learn/AcePlay/AcePlay.playground/Pages/Protocols.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/Protocols.xcplaygroundpage/Contents.swift index fa880fd..59ef2ef 100644 --- a/learn/AcePlay/AcePlay.playground/Pages/Protocols.xcplaygroundpage/Contents.swift +++ b/learn/AcePlay/AcePlay.playground/Pages/Protocols.xcplaygroundpage/Contents.swift @@ -106,3 +106,111 @@ let generator = LinearCongruentialGenerator() print("Here is a random number: \(generator.random())") print("Here is another random number: \(generator.random())") + + + + + + + +// 类类型专属协议 +protocol SomeClassOnlyProtocol: class { + func haha() -> String +} + +class HahaClass: SomeClassOnlyProtocol { + func haha() -> String { + return "Haha Class" + } +} +// 只能Class继承 +//struct HahaStruct : SomeClassOnlyProtocol { +// func haha() -> String { +// return "Haha Struct" +// } +//} + +let h = HahaClass() +print(h.haha()) + + + +// 协议合成 +// 有时候需要同时遵循多个协议,以将多个协议采用 SomeProtocol & AnotherProtocol 这样的格式进行组合 +protocol Named { + var name: String { get } +} + +protocol Aged { + var age: Int { get } +} + +struct SomeOne: Named, Aged { + var name: String + var age: Int +} + + +func wishHappyBirthday(to celebrator: Named & Aged) { + print("Happy Birthday, \(celebrator.name), you're \(celebrator.age)") +} +wishHappyBirthday(to: SomeOne(name: "Ace", age: 18)) + + +// 检查协议一致性 +protocol Area { + var area: Double { get } +} + +class Circle: Area { + var radius: Double + let pi = 3.1415927 + var area: Double { + get { + return pi*radius*radius + } + } + + init(radius: Double) {self.radius = radius } +} + + +class Country: Area { + var area: Double + init(area: Double) { self.area = area } +} + +class Animal { + var legs: Int + init(legs: Int) { self.legs = legs } +} + +let objects: [AnyObject] = [ + Circle(radius: 45), + Country(area: 960), + Animal(legs: 4) +] + +for o in objects { + if let oa = o as? Area { + print("Area is \(oa.area)") + } else { + print("Something that does not have area") + } +} + + + +// 协议扩展 +// 协议可以通过扩展来为遵循协议的类型提供属性、方法以及下标的实现。通过这种方式,可以基于协议本身来实现这些功能,而无需在每个遵循协议的类型中都重复同样的实现,也无需使用全局函数。 +extension RandomNumberGenerator { + func randomBool() -> Bool { + return random() > 0.5 + } +} + +let generator1 = LinearCongruentialGenerator() +print(generator1.randomBool()) + + + diff --git a/learn/AcePlay/AcePlay.playground/Pages/TypeCasting.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/TypeCasting.xcplaygroundpage/Contents.swift index 15f907b..cee1c8e 100644 --- a/learn/AcePlay/AcePlay.playground/Pages/TypeCasting.xcplaygroundpage/Contents.swift +++ b/learn/AcePlay/AcePlay.playground/Pages/TypeCasting.xcplaygroundpage/Contents.swift @@ -63,8 +63,8 @@ print("------------------------------------------------------------------") // 向下转型 -// 某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试向下转到它的子类型,用类型转换操作符(as? 或 as!) -// 因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式as? 返回一个你试图向下转成的类型的可选值。强制形式 as! 把试图向下转型和强制解包转换结果结合为一个操作 +// 某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,可以尝试向下转到它的子类型,用类型转换操作符(as? 或 as!) +// 因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式as? 返回一个试图向下转成的类型的可选值。强制形式 as! 把试图向下转型和强制解包转换结果结合为一个操作 for m in library { if let movie = m as? Movie { @@ -123,7 +123,7 @@ for t in things { // 注意:Any类型可以表示所有类型的值,包括可选类型 -// Swift会在你用Any类型来表示一个可选值的时候,给一个警告。如果确实想使用Any类型来承载可选值,你可以使用as操作符显式转换为Any +// Swift会在用Any类型来表示一个可选值的时候,给一个警告。如果确实想使用Any类型来承载可选值,可以使用as操作符显式转换为Any let optionalNumber: Int? = 3 // things.append(optionalNumber) // 会有warning things.append(optionalNumber as Any) // 不会有warning diff --git a/learn/AcePlay/AcePlay.playground/contents.xcplayground b/learn/AcePlay/AcePlay.playground/contents.xcplayground index e710ae5..b33f343 100644 --- a/learn/AcePlay/AcePlay.playground/contents.xcplayground +++ b/learn/AcePlay/AcePlay.playground/contents.xcplayground @@ -21,5 +21,7 @@ + + \ No newline at end of file diff --git a/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate b/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate index 5ea7ff6..957e76c 100644 Binary files a/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate and b/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate differ