学ぶことと準備
入門の構造体と関数を理解したら、データの変更がどこへ影響するかを学びましょう。例はそれぞれ独立しています。main.swiftの全体を置き換えて swift main.swift で実行します。
Windowsでは 入門のコンパイル手順と同じく、main.swiftを書き換えるたびにコンパイルして実行します。
構造体は値としてコピーする
構造体を別の変数に代入すると値がコピーされます。プロパティを変更するメソッドには mutating が必要です。変更するインスタンスはvarで持ちます。
struct Counter {
private(set) var count = 0
mutating func increment() { count += 1 }
}
var first = Counter()
var second = first
second.increment()
print(first.count)
print(second.count)0
1private(set) は外から読み取れる一方、直接の書き換えは型の内部に制限します。first.count = 10 はこの型の外ではコンパイルエラーです。
クラスは同じ実体を参照する
クラスのインスタンスを代入すると、同じ実体への参照を共有します。letは参照の差し替えを禁止しますが、参照先のvarプロパティの変更までは禁止しません。
final class Counter {
private(set) var count = 0
func increment() { count += 1 }
}
let first = Counter()
let second = first
second.increment()
print(first.count)
print(second.count)
print(first === second)1
1
true=== は同じインスタンスかを調べます。final は継承を禁止する指定です。同じ実体を共有する必要があるかを基準に構造体とクラスを選びます。
initで初期値を決める
クラスでは init を定義して、作成時に必要な値を受け取ります。self は現在のインスタンスを指します。引数とプロパティが同名のときに区別できます。
final class Product {
let name: String
let price: Int
init(name: String, price: Int) {
self.name = name
self.price = price
}
func label() -> String { return "\(name): \(price)円" }
}
let pen = Product(name: "ペン", price: 120)
print(pen.label())ペン: 120円プロトコルと拡張
プロトコルは型に求める機能を定義します。以下のNamedはnameを読めることを要求します。extension で共通のメソッドを追加すると、適合した型が使えます。
protocol Named { var name: String { get } }
extension Named {
func greeting() -> String { return "こんにちは、\(name)さん" }
}
struct Member: Named { let name: String }
let member = Member(name: "Mity")
print(member.greeting())こんにちは、Mityさん練習:在庫を守る
Stock構造体を作り、在庫が1以上のときだけ1個販売できるsellメソッドを追加します。在庫1から2回販売し、true、false、0と表示してください。
解答例と結果を確認する
まず自分で書いてから、処理の順番と結果を比べましょう。
struct Stock {
private(set) var count: Int
init(count: Int) { self.count = max(0, count) }
mutating func sell() -> Bool {
guard count > 0 else { return false }
count -= 1
return true
}
}
var stock = Stock(count: 1)
print(stock.sell())
print(stock.sell())
print(stock.count)true
false
0