index, AV, AppleScript, Bicycle, Cinema, DTM, Dairy, Dev, Fashion, Fitness, Game, Health, Help, Lyrics, Meal, Motor, Motorcycle, Music, Objective-C, PC, PDA, Phone, Robot, S15S, Stationary, Swift, Text, Travel, V36, Watch
定数と変数の名前にはUnicode文字を含むほぼ任意の文字を使用できる。
let maximumNumberOfLoginAttempts = 10 var currentLoginAttempt = 0 var x =0.0, y = 0.0, z = 0.0 var welcomeMEssage: String var red, green, blue: Double
let possbleNumber = "123" let convertedNumber = Int(possbleNumber) // convertedNumberはInt?またはoptional Int. var serverResponseCode: Int? = 404 // actual value. serverResponseCode = nil // now contains no value. var surveyAnswer: String? // Forced Unwrapping if convertedNumber != nil { ... } // Optional Binding (if let constantName = someOptional {} ) if let actualNumber = Int(possibleNumber) {...}
let names = ["Anna", "Alex", "Brian", "Jack"] for name in names { print("Hello, \(name)!") }
let numberOfLegs = ["spider":8, "ant": 6, "cat": 4] for (animalName, legCount) in numberOfLegs { print("\(animalName)s have \(legCount) legs") }
for index in 1...5 { print("\(index) times 5 is \(index * 5)") }
let base = 3 let power = 10 var answer = 1 for _ in 1...power { answer *= base }
let minutes = 60 for tickMark in 0..<minutes { // 60 times. }
let minuteInterval = 5 for tickMark in stride(from: 0, to: minutes, by: minuteInterval) { // 0, 5, 10...50, 55 }
while condition { statement }
repeat { statement } while condition
if condition { statement } else if condition { statement } else { statement }
breakしなくてもcaseの最後に次のcaseにfallthroughされない。
途中で抜けるためにbreak使用可。
switch 'some value to consider' { case value1: respond to value 1 case value2, value3: respond to value 2 or 3 default: otherwise, do something else }
Interval Matching
case 0: ... case 1..<5: ... case 5..<12: ... default: ...
Tuples
case (0, 0): ... case (_, 0): ... case (-2...2, -2...2): ... default: ...
Value Bindings
let anotherPoint = (2, 0) switch anotherPoint { case (let x, 0): print ("on the x-axis with an x value of \(x)") case (0, let y): print("on the y-axis with a y value of \(y)") case let (x, y): print("somewhere else at (\(x), \(y))") }
Where
let yetAnotherPoint = (1, -1) switch yetAnotherPoint { case let (x, y) where x == y: print("(\(x), \(y)) is on the line x == y") ...
gameLoop: while square != finalSquare { ... switch square + diceRoll { ... case finalSquare: break gameLoop case let newSquare where newSquare > finalSquare: continue gameLoop ... }
guard文は条件がtrueであればそのまま処理を続け、trueでなければelse節のコードが実行される。else節は必ず存在しなければならない。
guard let name = person["name"??] else { return }
ビルトインでサポートされるAPI可用性のチェック。ifまたはguard文で使用。
if #available(iOS 9, OSX 10.10, *) { ... } else { それ以前 } if #available(platform name version, ..., *) { statements to execute if the APIs are available } else { fallback statements to execute if the APIs are unavailable }
platform nameにはiOS, OSX, watchOSを使用する。iOS 8、あるいはiOS 8.3といった形でも指定できる。
//greet(person:) func greet(person: String) -> String { let greeting = "Hello, " + person + "!" return greeting }
複数のパラメータ
func greet(person: String, alreadyGreeted: Bool) -> String { ... } without return values
func greet(person: String) { ... } // 実際にはVoidが返される。Voidとは空のタプル ()
multiple return values
func minMax(array: [Int]) -> (min: Int, max: Int) { ... }
Optional Tuples Return Types
func minMax(array: [Int]) -> (min: Int, max: Int)? { ... } // (min: Int?, max: Int?) とは異る
Function Argument Labels and Parameter Names
func someFunction(firstParameterName: Int, secondParameterName: Int){ ... } -> someFunction(firstParameterName: 1, secondParameterName: 2) func someFunction(argumentLabel parameterName: Int) { ... } func greet(person: String, from hometown: String) -> String { ... } -> greet(perton: "Bill", from: "Cupertino")
omitting argument labels
func someFunction(_ firstParameterName: Int, secondParameterName: Int) { ... }
default parameter values
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) { ... } -> someFuntion(parameterWithoutDefault: 4)
variadic parameters 可変長パラメータ
func arithmeticMean(_ numbers: Double...) -> Double { ... for number in numbers { ... } ... }
In-Out Parameters
func swapTwoInts(_ a: inout Int, _ b: inout Int) { ... } -> swapTwoInts(&someInt, &anotherInt)
Function Types
func addTwoInts(_ a: Int, _ b: Int) -> Int { ... } => (Int, Int) -> Int var mathFunction: (Int, Int) -> Int = addTwoInts mathFunction(2, 3) func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int){ ... }
{ ('parameters') -> 'return type' in 'statements' } func backward(_ s1: String, _ s2: String) -> Bool { return s1 > s2 } reversedNames = names.sorted(by: backward) reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 }) reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 }) reversedNames = names.sorted(by: { s1, s2 in s1 > s2 }) reversedNames = names.sorted(by: { $0 > $1 }) reversedNames = names.sorted(by: >)
Trailing Closures - 後置クロージャ
func someFunctionThatTakesAClosure(closure: () -> Void){ ... } someFunctionThatTakesAClosure(closure: { ... }) someFunctionThatTakesAClosure(){ ... } reversedNames = names.sorted() { $0 > $1 } reversedNames = names.sorted { $0 > $1 } // クロージャ式・関数が唯一の引数で後置する場合には()不要
複数のクロージャを引数とする関数は、最初の引数のラベルを省略し、残りの引数にラベルする。
func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void){ ... } loadPicture(from: someServer) { picture in someView.currentPicture = picture } onFailure: { ... }
値のキャプチャ
func makeIncrementer(forIncrement amout: Int) -> () -> Int { var runningTotal = 0 func incrementer() -> Int { runningTotal += amout return runningTotal } return incrementer } let incrementByTen = makeIncrementer(forIncrement: 10) incrementByTen() // returns a value of 10 incrementByTen() // returns a value of 20 incrementByTen() // returns a value of 30 let incrementBySeven = makeIncrementer(forINcrement: 7) incrementBySeven() // returns a value of 7 incrementByTen() // returns a value of 40
クロージャは参照型である。
let alsoIncrementByTen = incrementByTen alsoIncrementByTen() // returns a value of 50 incrementByTen() // returns a value of 60
クロージャをエスケープする。(@noescapeはobsolete? @escapingを使用する)
@escapingをマークせずにエスケープするとコンパイルエラー。
var completionHandlers: [() ->Void]() func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) { completionHandlers.append(completionHandler) // 関数の外側で宣言された配列に追加。 }
この辺りはよく分からない。再度勉強すること。https://docs.swift.org/swift-book/LanguageGuide/Closures.html
自動クロージャ Autoclosures
enum SomeEnumeration { ... } enum CompassPoint { case north case south case east case west } enum Planet { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune } var directionToHead = CompassPoint.west directionToHead = .east // 一度型が決まれば略記可能。
switch構文における列挙型の一致
directionToHead = .south switch directionToHead { case .north: ... case .south: ... ... } // 全てのcaseを扱わないならdefault節が必須。
Iteration over Enumeration Cases
enum Beverage: CaseIterable { vase coffee, tea, juice } let numberOfChoices = Beverage.allCases.count for beverage in Beverage.allCases { ... }
列挙型 関連値
enum Barcode { case UPCA(Int, Int, Int, Int) case QRFode(String) } var productBarcode = Barcode.UPCA(8, 85909, 51226, 3) productBarcode = .QRCode("ABCDEFGHIJKLMNOP") switch productBarcode { case .UPCA(let numberSystem, let manufacturer, let product, let check): print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).") case .QRCode(... } // 全ての関連値を定数・変数として取り出す場合にはcase前にアノテーションとしてletを置く。 case let .UPCA(numberSystem, manufacturer, product, check): print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
Raw値 Raw Value
// 全てユニークな値にする必要がある。 enum ASCIIControlCharacter: Character { case Tab = "\t" case LineFeed = "\n" case CarriageReturn = "\r" }
暗黙のうちに割り当てられるraw値
enum Planet: Int { case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune } // 順に1、2、3…が割り当てられる。 enum CompassPoint: String { case North, South, East, West } // それぞれ"North"などの文字列が割り当てられる。 let earthsOrder = Planet.Earth.rawValue // raw値を取り出す。 let possiblePlanet = Planet(rawValue: 7) // possiblePlanetはPlanet?型。raw値による初期化。
public protocol CaseIterable { /// A type that can represent a collection of all values of this type. associatedtype AllCases : Collection where Self.AllCases.Element == Self /// A collection of all values of this type. public static var allCases: Self.AllCases { get } }
enum Direction2: CaseIterable { case east case west case north case south } // [__lldb_expr_8.Direction1.east, __lldb_expr_8.Direction1.west, __lldb_expr_8.Direction1.north, __lldb_expr_8.Direction1.south] print(Direction2.allCases)
列挙型そのものを渡すことができる。
struct Sample { var characters: String enum CodingKeys: String, CodingKey { case characters } } extension Sample: Decodable { init(from decoder: Decoder) throw { let values = try decoder.container(keyedBy: CodingKeys.self) ... }
列挙型の定義そのものを渡すことができる様子。例では"- Swift.String #0" が渡される。
class SomeClass { ... } struct SomeStructure { ... } // クラス・構造体の名前は大文字から。プロパティ・メソッドは小文字から始まる文字列とする。
struct Resolution { var width = 0 var height = 0 } class VideoMode { var resolutin = Resolution() var interlaced = false var frameRate = 0.0 var name: String? // nilが代入される }
インスタンス生成
let someResolution = Resolution() let someVideoMode = VideoMode()
プロパティへのアクセス
someResolution.width someVideoMode.resolution.width someVideoMode.resolution.width = 1280
構造体のメンバーワイズイニシャライザ。クラスにはない。
let vga = Resolution(width: 640, height: 480) // 自動生成されるイニシャライザ。
struct FixedLenghRange { var firstValue: Int let length: Int } var rangeOfThreeItems = FixedLenghRange(firstValue: 0, length: 3) class DataManager { lazy var importer = DataImoprter() var data = [String]() }
構造体のインスタンスを生成して定数に代入すると、インスタンスのプロパティは変数であっても変更することができない。
コンピューテッドプロパティ
struct Point { var x = 0.0, y = 0.0 } struct Size { var width = 0.0, heigth = 0.0 } struct Rect { var origin = Point() var size = Size() var center: Point { get { let centerX = origin.x + (size.width / 2) let centerY = origin.y + (size.height / 2) return Point(x: centerX, y: centerY) } set(newCenter) { origin.x = newCenter.x - (size.width / 2) origin.y = newCenter.y - (size.height / 2) } } } // 簡易setter宣言 - 新しい値の名前を定義していない場合、デフォルトの名前newValueが使用される。 set { origin.x = newValue.x - (size.width / 2) origin.y = newValue.y - (size.height / 2) }
setterがなくgetterのみのコンピューテッドプロパティは読取専用。
読取専用の場合、getキーワードと{}を省略できる。
struct Cuboid { var width = 0.0, height = 0.0, depth = 0.0 var volume: Double { return width * height * depth } }
プロパティオブザーバ
class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps){ // 値が保管される直前に呼び出される。 ... // newTotalStepsを定義しなければnewValueが利用できる。 } didSet { // 値が保管された直後に呼び出される。 ... // oldValueを利用する。別のパラメータ名を付けることはできない。 } } }
Property Wrappers
@propertyWrapper struct TwelveOrLess { private var number: Int init() { self.number = 0 } var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } } struct SmallRectangle { @TwelveOrLess var height: Int @TwelveOrLess var width: Int }
つまり、wrappedValueの扱いを定義したwrapperを作成し、それをプロパティに設定できる?
このあたりは新しいらしく日本語訳なし。初期値の定義についてかなり詳しく解説されている。
タイププロパティシンタックス
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 } } SomeStructure.storedTypeProperty
class Counter { var count = 0 func increment() { count += 1 } func increment(by amount: Int) { count += amount } func reset() { count = 0 } }
struct Point { var x = 0.0, y = 0.0 mutating func moveBy(deltaX: Double, y deltaY: Double) { x += deltaX y += deltaY } } var somePoint = Point(x: 1.0, y: 1.0) somePoint.moveBy(x: 2.0, y: 3.0) // -> (3.0, 4.0)
こうも書ける。
struct Point { var x = 0.0, y = 0.0 mutating func moveBy(deltaX: Double, deltaY: Double){ self = Point(x: x + deltaX, y: y + deltaY) } }
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となる。
class SomeClass { class func someTypeMethod() { // some. } } SomeClass.someTypeMethod()
struct LevelTracker { static var highestUnlockedLevel = 1 static func unlockLevel(level: Int) { if level > highestUmnlockedLevel { highestUnlockedLevel = level } } static func levelIsUnlocked(level: Int) -> Bool { return level <= highestUnlockedLevel } var currentLevel = 1 mutating func advanceToLevel(level: Int) -> Bool { if LevelTracker.levelIsUnlocked(level){ currentLevel = level return true } else { return false } } }
subscript(index: Int) -> Int { get { ... } set(newValue){ ... } // 定義しなければ'newValue'がパラメータとなる。 } subscript(index: Int) -> Int { // setがない場合にはgetキーワードを省略できる。 } struct TimesTable { let multiplier: Int subscript(index: Int) -> Int { return multiplier * index } } let threeTimesTable = TimesTable(multiplier: 3) threeTimesTable[6] // -> 18
subscript(row: Int, column: Int) -> Double {...}
class Vehicle { var currentSpeed = 0.0 var description: String { return "traveling at \(currentSpeed) miles per hour" } func makeNoise(){ // do nothing. } } class SomeSubclass: SomeSuperClass { // サブクラス定義 } class Bicycle: Vehicle { var hasBasket = false }
class Train: Vehicle { override func makeNoise() { //... } }
class Car: Vehicle { var gear = 1 override var description: String { return super.description + " in gear \(gear)" } }
class AutomaticCar: Car { override var currentSpeed: Double { didSet { gear = Int(currentSpeed / 10.0) + 1 } } }
init (){ // ... } struct Fahrenheit { var temperature: Double init(){ temperature = 32.0 } } struct Fahrenheit { var temperature = 32.0 } struct Celsius { var temperatureInCelsius: Double init(fromFahrenheit fahrenheit: Double){ temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double){ temperatureInCelsius = kelvin - 273.15 } init(_ celsius: Double){{ temperatureInCelsius = celsius } }
class SurveyQuestion { var text: String var response: String? // オプショナル型プロパティ init(text: String){ self.text = text } func ask(){ print(text) } }
struct Size { var width = 0.0, height = 0.0 } let twoByTwo = Size(width: 2.0, height: 2.0)
struct Animal { let species: String init?(species: String){ if species.isEmpty { return nil } self.species = species } }
enum TemperatureUnit { case Kelvin, Celsius, Fahrenheit init?(symbol: Character){ switch symbol { case "K": self = .Kelvin case "C": self = .Celsius case "F": sefl = .Fahrenheit default: return nil } } }
class SomeClass { let someProperty: SomeType = { //... return someValue }() }
class SomeClass { required init() { // something. } }
class SomeClass { let someProperty: SomeType = { // something... return someValue // SomeTypeと同じ型の戻り値を返す。 }() // クロージャの後に()が必要。 }
deinit { // something. }
class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() let roomCount = johjn.residence!.numberOfRooms // 実行時エラー if let roomCount = john.residence?.numberOfRooms { // roomCountが存在する場合 } else { // 存在しない場合 }
この例では、residenceがnilの場合を考えてnumberOfRoomsはInt?型の値を返す。
if let firstRoomName = john.residence?[0].name { ... }
enum VendingMachineError: Error { case InvalidSelection case InsufficientFunds(coinsNeeded: Int) case outOfStock }
throw VendingMachineError.InsufficientFunds(coinsNeeded: 5)
func conThrowErrors() throws -> String func cannotThrowErrors() -> String
struct PurchasedSnack { let name: String init(name: String, vendingMachine: VendingMachine) throws { try vendingMachine.vend(itemNamed: name) self.name = name } }
do { try 'expression' 'statements' } catch 'pattern1' { 'statements' } catch 'pattern2' where 'condition' { 'statements' }
func processFile(filename: String) throws { if exists(filename) { let file = open(filename) defer { close(file) } while let line = try file.readline() { // ファイルを扱う。 } // この場所でdeferのclose(file)が呼び出される。 } }
class MediaItem { var name: String init(name: String) { self.name = name } } class Movie: MediaItem { var director: String init(name: String, director: String) { self.director = director super.init(name: name) } } class Song: MediaItem { var artist: String init(name: String, artist: String) { self.artist = artist super.init(name: name) } } /// for item in library { if item is Movie { movieCount += 1 } else if item is Song { songCount += 1 } } // for item in library { if let movie = item as? Movie { ... } else if let song = item as? Song { ...} } for object in someObjects { let movie = object as! Movie //... } for movie in someObjets as! [Movie] { ... }
let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue
extension SomeType { ... } extension SomeType: SOmeProtocol, AnotherProtocol { ... }
extension Rect { init(center: Point, size: Size){ let originX = center.x - (size.width / 2) let originY = cneter.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } }
extension Int { func repetitions(task: () -> Void) { for _ in 0..<self { task() } } } 3.repetitions({ print("hello!") }) // 後置クロージャ 3.repetitions { print("hello!") }
extension Int { mutating func square() { self = self * self } } // 数値の右端からn番目の数値を返す。123456789[0]なら9 extention Int { subscript(digitIndex: Int) -> Int { var decimalBase = 1 for _ in 0..<digitIndex { decimalBase *= 10 } return (self / decimalBase) % 10 } } extension Int { enum Kind { case Negative, Zero, Positive } var kind: Kind { switch self { case 0: return .Zero case let x where x > 0: return .Positive default: return .Negative } } }
protocol SomeProtocol { // プロトコルの定義 } struct SomeStructure: FirstProtocol, AnotherProtocol { // 構造体の定義 } class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { // クラスの定義 }
protocol SomeProtocol { var mustBeSettable: Int { get set } var doesNotNeedToBeSettable: Int { get } } protocol AnotherProtocol { static var someTypeProperty: Int { get set } }
protocol FullyNamed { var fullName: String { get } } struct Person: FullyNamed { var fullName: String } let john = Person(fullName: "John Appleseed")
class Starship: FullyNamed { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String{ return (prefix != nil ? prefix! + " " : "") + name } } var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
protocol SomeProtocol { static func someTypeMethod() } /// protocol RandomNumberGenerator { func random() -> Double } class LinearCongruentialGenerator: RandomNumberGenerator { var lastRandom = 42.0 let m = 1339968.0 let a = 3877.0 let c = 29573.0 func random() -> Double { lastRandom = ((lastRandom * a -+ c) % m) return lastRandom / m } } let generator = LinearCongruentialGEnerator() generator.random()
protocol Togglable { mutating func toggle() } enum OnOffSwitch: Togglable { case Off, On mutating func toggle() { switch self { case Off: self = On case On: self = Off } } } var lightSwitch = OnOffSwitch.Off lightSwitch.toggle()
protocol SomeProtocol { init(somePrameter: Int) } class SomeClass: SomeProtocol { required init(someParameter: Int){ // 実装 } } /// protocol SomeProtocol { init() } class SomeSuperClass { init () { // 実装 } } class SomeSubClass: SomeSuperClass, SomeProtocol { // SomeProtocolからのrequiredと、SomeSuperClassからのoverride required override init(){ // 実装 } }
class Dice { let sides: Int let generator: RandomNumberGenerator init(sides: Int, generator: RandomNumberGenerator){ self.sides = sides self.generator = generator } func roll() -> Int { return Int(generator.random() * Double(sides)) + 1 } }
protocol DiceGame { var dice: Dice { get } func play() } protocol DiceGameDelegate: AnyObject { // <- クラス限定プロトコル v5.3 func gameDidStart(_ game: DiceGame) func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) func gameDidEnd(_ game: DiceGame) }
protocol TextRepresentable { var textualDescription: String { get } } extension Dice: TextRepresentable { var textualDescription: String { return "A \(sides)-sided dice" } }
let things: [TextRepresentable] = [game, d12, simonTheHamster] for thing in things { print(thing.textualDescription) }
protocol InheritingProtocol: SomeProtocol, AnotherProtocol { ... } protocol PrettyTextualRepresentable: TextRepresentable { var prettyTextualDescription: String { get } }
protocol SomeClassOnlyProtocol: AnyObject, SomeInteritedProtocol { ... }
protocol Named { var name: String { get }} protocol Aged {var age: Int { get }} protocol Person: Named, Aged { var name: String var age: Int } func wishHappyBirthday(to celebrator: Named & Aged){ ... } let birthdayPerson = Person(name: "Malcomlm", age: 21) wishHappyBirthday(to: birthdayPerson)
protocol HasArea { var area: Double { get } } class Circle: HasArea { ... } class Country: HasArea { ... } class Animal { ... } let objects: [AnyObject] = [ Circle(radius: 2.0), Country(area: 243_610), Animal(legs: 4) ] for object in objects { if let objectWithArea = object as? HasArea { ... } else { ... } }
extension RandomNumberGenerator { func randomBool() -> Bool { return random() > 0.5 } }
extension Collection where Element: TextRepresentable { func allEqual() -> Bool { for element in self { if element != self.first { return false } } return true } }
func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA } var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt) // Generic function func swapTwoValues<T>(_ a: inout T, _ b: inout T) { ... } swapTwoValues(&someInt, &anotherInt) // Swift standard library has 'swap(_:_:)' function. struct Stack<Element> { var items = [Element]() mutating func push(item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } } var stackOfStrings = Stack<String>() stackOfStrings.push("uno") stackOfStrings.push("dos") // Extension extension Stack { var topItem: Element? { return items.isEmpty ? nil : items[items.count - 1] } } // Element型のオプショナル値を返す。 // 型制約シンタックス func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U){...}
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? { for (index, value) in array.enumerated() { if value == valueToFind { return index } } return nil } func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? { for (index, value) in array.enumerated() { if value == valueToFind { return index } } return nil }
// Associated Types protocol Container { associatedtype Item mutating func appen(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } } struct Stack<Element>: Container { var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() // これ、確実にElementが返るとは限らないね。 // items.count == 0ならnilを返すことにして戻り値はElement!がよさそう。 } mutating func append(_ item: Element) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Element { return items[i] } }
extension Array: Container {}
//Associated typeに制限を付加する。 protocol Container { associatedtype Item: Equatable mutating func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } } // 関連型の制限をうけたプロトコルを使用する protocol SuffixableContainer: Container { associatedtype Suffix: SuffixableContainer where Suffix.Item == Item func suffix(_ size: Int) -> Suffix }
この節については理解が進んでいない。また後日。邦訳版とはまったく内容が異なるため原文を読むこと。
// 二項演算子 struct Vector2D { var x = 0.0, y = 0.0 } func + (left: Vector2D, right: Vector2D) -> Vector2D { return Vector2D(x: left.x + right.x, y: left.y + right.y) } // 単項演算子 // これは前置単項演算子のためprefixを付加する。 extension Vector2D { static prefix func - (vector: Vector2D) -> Vector2D { return Vector2D(x: -vector.x, y: -vector.y) } } let negative = -positive // 複合代入演算子 extension Vector2D { static func += (left: inout Vector2D, right: Vector2D) { left = left + right } } // Equivalence Operators extension Vector2D: Equatable { static func == (left: Vector2D, right: Vector2D) -> Bool { return (left.x == right.x) && (left.y == right.y) } }