美文网首页
第四部分 泛型 ~ 高级运算符

第四部分 泛型 ~ 高级运算符

作者: wg689 | 来源:发表于2022-07-03 00:22 被阅读0次
    
    import UIKit
    
    var greeting = "Hello, playground"
    
    //上面 swapTwoValues(_:_:) 例子中,占位类型 T 是一个类型参数的例子,类型参数指定并命名一个占位类型,并且紧随在函数名后面,使用一对尖括号括起来(例如 <T>)。
    
    func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
        let temporaryA = a
        a = b
        b = temporaryA
    }
    
    func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
        let temporaryA = a
        a = b
        b = temporaryA
    }
    
    //泛型扩展
    
    struct Stack<Element> {
        var items: [Element] = []
        mutating func push(_ item: Element) {
            items.append(item)
        }
        mutating func pop() -> Element {
            return items.removeLast()
        }
    }
    //注意:这个扩展并没有定义类型参数列表。相反的,Stack 类型已有的类型参数名称 Element,被用在扩展中来表示计算型属性 topItem 的可选类型。
    //
    //extension Stack2 {
    //    var topItem: Element? {
    //        return items.isEmpty ? nil : items[items.count - 1]
    //    }
    //}
    
    
    
    //注意:这个扩展并没有定义类型参数列表。相反的,Stack 类型已有的类型参数名称 Element,被用在扩展中来表示计算型属性 topItem 的可选类型。
    //
    //func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    //    // 这里是泛型函数的函数体部分
    //}
    
    
    func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
        for (index, value) in array.enumerated() {
            if value == valueToFind {
                return index
            }
        }
        return nil
    }
    //遵循 Equatable 协议的类型都可以安全地用于 findIndex(of:in:) 函数,因为其保证支持等式操作符。为了说明这个事情,当定义一个函数时,你可以定义一个 Equatable 类型约束作为类型参数定义的一部分:
    
    
    //关联类型实践
    
    protocol Container {
        associatedtype Item //协议定义了一个关联类型 Item:
    //    指定 Item 为 Int 类型,即 typealias Item = Int,从而将 Container 协议中抽象的 Item 类型转换为具体的 Int 类型。
        mutating func append(_ item: Item)
        var count: Int { get }
        subscript(i: Int) -> Item { get }
    }
    
    struct Stack2: Container {
        // IntStack 的原始实现部分
        var items: [Int] = []
        mutating func push(_ item: Int) {
            items.append(item)
        }
        mutating func pop() -> Int {
            return items.removeLast()
        }
        // Container 协议的实现部分
        typealias Item = Int
        mutating func append(_ item: Int) {
            self.push(item)
        }
        var count: Int {
            return items.count
        }
        subscript(i: Int) -> Int {
            return items[i]
        }
    }
    //如果你在上面的代码中删除了 typealias Item = Int 这一行,一切也可正常工作,因为 Swift 清楚地知道 Item 应该是哪种类型。
    
    extension Array: Container {}
    
    
    //给关联类型添加约束
    //
    
    protocol Container3 {
        associatedtype Item: Equatable //你可以在协议里给关联类型添加约束来要求遵循的类型满足约束。例如,下面的代码定义了 Container 协议, 要求关联类型 Item 必须遵循 Equatable 协议:
        mutating func append(_ item: Item)
        var count: Int { get }
        subscript(i: Int) -> Item { get }
    }
    
    protocol SuffixableContainer: Container3 {
        associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
        //就像上边例子中 Container 的 Item 类型一样。Suffix 拥有两个约束:它必须遵循 SuffixableContainer 协议(就是当前定义的协议),以及它的 Item 类型必须是和容器里的 Item 类型相同。Item 的约束是一个 where 分句
        func suffix(_ size: Int) -> Suffix
    }
    
    
    //
    //
    //extension Stack2: SuffixableContainer {
    //    func suffix(_ size: Int) -> Suffix {
    //        var result = Stack()
    //        for index in (count-size)..<count {
    //            result.appent(self[index])
    //        }
    //        return result
    //    }
    //}
    //var stackOfInts = Stack<Int>()
    //stackOfInts.append(0)
    //stackOfInts.append(20)
    //stackOfInts.append(30)
    //
    //let suffix = stackOfInts.suffix(2)
    //
    //
    
    
    
    //在关联类型约束里使用协议
    
    
    
    //不透明类型
    protocol Shape {
        func draw() -> String
    }
    
    struct Triangle: Shape {
        var size: Int
        func draw() -> String {
            var result: [String] = []
            for length in 1...size {
                result.append(String(repeating: "*", count: length))
            }
            return result.joined(separator: "\n")
        }
    }
    
    let smallTriangle = Triangle(size: 3)
    print(smallTriangle.draw())
    
    struct FlippedShape<T: Shape>: Shape {
        var shape: T
        func draw() -> String {
            let lines = shape.draw().split(separator: "\n")
            return lines.reversed().joined(separator: "\n")
        }
    }
    
    let flippedTriangle = FlippedShape(shape: smallTriangle)
    print(flippedTriangle.draw())
    
    
    struct joinedShape<T: Shape, U: Shape>: Shape {
        var top: T
        var bottom: U
        func draw() -> String {
            return top.draw() + "\n" + bottom.draw()
        }
    }
    let joinedTriangles = joinedShape(top: smallTriangle, bottom: flippedTriangle)
    print("--joinedTriangles-")
    print(joinedTriangles.draw())
    //你可以认为不透明类型和泛型相反。泛型允许调用一个方法时,为这个方法的形参和返回值指定一个与实现无关的类型。举个例子,下面这个函数的返回值类型就由它的调用者决定:
    
    
    struct Square: Shape {
        var size: Int
        func draw() -> String {
           let line = String(repeating: "*", count: size)
           let result = Array<String>(repeating: line, count: size)
            return result.joined(separator: "\n")
        }
    }
    
    func makeTrapeZoid() -> some Shape {
        let top = Triangle(size: 2)
        let middle = Square(size: 2)
        let bottom = FlippedShape(shape: top)
        let trapezoid = joinedShape(
           top: top,
           bottom: joinedShape(top: middle, bottom: bottom)
        )
        return trapezoid
    }
    
    let trapezoid = makeTrapeZoid()
    print(trapezoid.draw())
    
    
    class Person {
        let name: String
        init(name: String) {
            self.name = name
            print("\(name) is being initialized")
        }
        deinit {
            print("\(name) is being deinitialized")
        }
    }
    
    var reference1: Person?
    var reference2: Person?
    var reference3: Person?
    
    reference1 = Person(name: "John Appleseed")
    // 打印“John Appleseed is being initialized”
    
    
    reference2 = reference1
    reference3 = reference1
    
    
    reference1 = nil
    reference2 = nil
    
    
    class Person2 {
        let name: String
        init(name: String) { self.name = name }
        var apartment: Apartment?
        deinit { print("\(name) is being deinitialized") }
    }
    
    class Apartment {
        let unit: String
        init(unit: String) { self.unit = unit }
        weak var tenant: Person2?
        deinit { print("Apartment \(unit) is being deinitialized") }
    }
    
    var john: Person2?
    var unit4A: Apartment?
    
    john = Person2(name: "John Appleseed")
    unit4A = Apartment(unit: "4A")
    
    john!.apartment = unit4A
    unit4A!.tenant = john
    
    
    john = nil
    unit4A = nil
    
    
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) {
            self.name = name
        }
        deinit { print("\(name) is being deinitialized") }
    }
    
    class CreditCard {
        let number: UInt64
        unowned let customer: Customer
        init(number: UInt64, customer: Customer) {
            self.number = number
            self.customer = customer
        }
        deinit { print("Card #\(number) is being deinitialized") }
    }
    
    
    var john2: Customer?
    
    john2 = Customer(name: "John Appleseed")
    john2!.card = CreditCard(number: 1234_5678_9012_3456, customer: john2!)
    john = nil
    
    class Department {
        var name: String
        var courses: [Course]
        init(name: String) {
            self.name = name
            self.courses = []
        }
    }
    
    class Course {
        var name: String
        unowned var department: Department
        unowned var nextCourse: Course?
        init(name: String, in department: Department) {
            self.name = name
            self.department = department
            self.nextCourse = nil
        }
    }
    
    let department = Department(name: "Horticulture")
    
    let intro = Course(name: "Survey of Plants", in: department)
    let intermediate = Course(name: "Growing Common Herbs", in: department)
    let advanced = Course(name: "Caring for Tropical Plants", in: department)
    
    intro.nextCourse = intermediate
    intermediate.nextCourse = advanced
    department.courses = [intro, intermediate, advanced]
    
    
    class Country {
        let name: String
        var capitalCity: City!
        init(name: String, capitalName: String) {
            self.name = name
            self.capitalCity = City(name: capitalName, country: self)
        }
    }
    
    class City {
        let name: String
        unowned let country: Country
        init(name: String, country: Country) {
            self.name = name
            self.country = country
        }
    }
    
    var country = Country(name: "Canada", capitalName: "Ottawa")
    print("\(country.name)'s capital city is called \(country.capitalCity.name)")
    // 打印“Canada's capital city is called Ottawa”
    
    
    class HTMLElement {
    
        let name: String
        let text: String?
    
        lazy var asHTML: () -> String = {
            if let text = self.text {
                return "<\(self.name)>\(text)</\(self.name)>"
            } else {
                return "<\(self.name) />"
            }
        }
        
        init(name: String, text: String? = nil) {
            self.name = name
            self.text = text
        }
        
        deinit {
            print("\(name) is being deinitialized")
        }
        
    }
    
    
    // 内存安全
    //默认情况下,Swift 会阻止你代码里不安全的行为。例如,Swift 会保证变量在使用之前就完成初始化,在内存被回收之后就无法被访问,并且数组的索引会做越界检查。
    
    
    // 向 one 所在的内存区域发起一次写操作
    var one = 1
    
    // 向 one 所在的内存区域发起一次读操作
    print("We're number \(one)!")
    
    //至少有一个是写访问
    //它们访问的是同一个存储地址
    //它们的访问在时间线上部分重叠
    
    var stepSize = 1
    func increment(_ number: inout Int) {
        number = number + stepSize
    }
    
    var copyOfStepSize = stepSize
    
    increment(&copyOfStepSize)
    
    stepSize = copyOfStepSize
    
    
    struct Player {
        var name: String
        var health: Int
        var energy: Int
        
        static let maxHealth = 10
        mutating func restoreHealth() {
            health = Player.maxHealth
        }
    }
    
    extension Player {
        mutating func shareHealth(with teammate: inout Player) {
    //        balance(&teammate.health, &health)
        }
    }
    
    var oscar = Player(name: "Oscar", health: 10, energy: 10)
    var maria = Player(name: "Maria", health: 5, energy: 10)
    oscar.shareHealth(with: &maria)  // 正常
    
    //运算符函数
    
    //类和结构体可以为现有的运算符提供自定义的实现。这通常被称为运算符重载。
    //下面的例子展示了如何让自定义的结构体支持加法运算符(+)。算术加法运算符是一个二元运算符,因为它是对两个值进行运算,同时它还可以称为中缀运算符,因为它出现在两个值中间。
    //例子中定义了一个名为 Vector2D 的结构体用来表示二维坐标向量 (x, y),紧接着定义了一个可以将两个 Vector2D 结构体实例进行相加的运算符函数:
    
    

    相关文章

      网友评论

          本文标题:第四部分 泛型 ~ 高级运算符

          本文链接:https://www.haomeiwen.com/subject/jozqmrtx.html