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(©OfStepSize)
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 结构体实例进行相加的运算符函数:
网友评论