コーディング · プログラミング言語
Swift入門チュートリアル(初心者向け)
結論
Swiftは、AppleがiPhone、iPad、Mac、Apple Watch、Apple TV向けのアプリのために作った、高速で安全なコンパイル型言語で、LinuxやWindowsでも動作します。print("Hello, world") を hello.swift に保存して swift hello.swift で実行します。let の定数と var の変数、型推論、値がないかもしれない場合のオプショナル、値のセマンティクスを持つ構造体と列挙型、プロトコル、do/try/catch によるエラー処理が中心的な内容です。
Swiftとは何か、何に使われるか
Swiftは、Objective-Cに代わるモダンな言語として2014年にAppleが発表し、2015年にオープンソース化されました。プロジェクトはswift.orgにあります。Appleプラットフォーム向けアプリの主要言語で、通常はSwiftUIやUIKitフレームワークと組み合わせて使います。サーバーサイドのコード(たとえばVaporフレームワーク)やコマンドラインツールにも使われます。この言語は、よくあるバグを防ぐよう設計されています。変数は初期化が必須で、配列は範囲をチェックし、nil は明示的に扱う必要があります。
Swiftのインストールと Hello, world の実行
Macでは、App StoreからXcodeをインストールするか、Xcodeのコマンドラインツールを入れます。LinuxとWindowsでは、swift.orgからツールチェーンをダウンロードします。swift --version で確認します。
print("Hello, world")swift hello.swift
# Hello, world
swiftc hello.swift -o hello # compile to a binary
./hello大きなプロジェクトでは、swift package init --type executable を実行してから swift run を実行します。Xcodeのプレイグラウンドも、気軽に試せる方法です。
定数、変数、基本の型
定数には let、変数には var を使います。let を優先しましょう。一度も変更されない var には、コンパイラが警告を出します。型は推論され、Swiftは数値型どうしを暗黙的に変換しません。
| 型 | 例 | 備考 |
|---|---|---|
Int | let n = 42 | 最近のプラットフォームでは64ビット |
Double | let x = 3.14 | デフォルトの浮動小数点型 |
Bool | let ok = true | true または false |
String | let s = "hi \(name)" | Unicodeテキスト。値型 |
Character | let c: Character = "é" | ユーザーが1文字と認識する単位 |
[Int], [String: Int] | [1, 2], ["a": 1] | 配列とディクショナリ |
let name = "Ada"
var count = 7
count += 1
let avg = Double(count) / 2 // explicit conversion
print("\(name) has \(count) items, avg \(avg)") // Ada has 8 items, avg 4.0
print(7 / 2, 7 % 2) // 3 1文字列リテラル内の \(expression) は、値を埋め込みます(文字列補間)。
制御構文
let score = 72
if score >= 90 {
print("A")
} else if score >= 70 {
print("B") // B
} else {
print("C")
}
for i in 0..<3 {
print(i, terminator: " ") // 0 1 2
}
print()
var n = 10
while n > 1 { n /= 2 }
print(n) // 1
let day = "SAT"
switch day {
case "SAT", "SUN":
print("weekend") // weekend
default:
print("weekday")
}switch は網羅的である必要があり、デフォルトでは次のケースに落ちず、範囲(case 90...100:)、タプル、列挙型のケースにマッチできます。
関数とクロージャ
引数には、呼び出し側が書く引数ラベルがあり、呼び出しが文章のように読めます。ラベルを省略するには _ を使います。クロージャは、波括弧で書く無名関数です。
func greet(_ name: String, with greeting: String = "Hello") -> String {
return "\(greeting), \(name)!"
}
print(greet("Lin")) // Hello, Lin!
print(greet("Lin", with: "Hi")) // Hi, Lin!
let nums = [3, 1, 2, 5]
let squares = nums.map { $0 * $0 }
let evens = nums.filter { $0 % 2 == 0 }
let sorted = nums.sorted(by: >)
print(squares, evens, sorted) // [9, 1, 4, 25] [2] [5, 3, 2, 1]$0 はクロージャの最初の引数を指します。クロージャが最後の引数のときは、括弧の後ろに書けます(トレイリングクロージャ構文)。
配列、ディクショナリ、セット
var fruits = ["apple", "pear"]
fruits.append("fig")
print(fruits.count, fruits[0], fruits.contains("fig")) // 3 apple true
var ages: [String: Int] = ["ann": 31, "bob": 25]
ages["cy"] = 40
for (person, age) in ages.sorted(by: { $0.key < $1.key }) {
print(person, age) // ann 31, bob 25, cy 40
}
print(ages["zed", default: 0]) // 0
let tags: Set = ["b", "a", "b"]
print(tags.count) // 2コレクションは値型です。配列を別の変数に代入すると、独立したコピーが作られます(実際のコピーは、どちらかが変更されたときまで遅延されます)。let の配列は、まったく変更できません。
特徴的な機能:オプショナル
値がないかもしれない場合は、String? と書くオプショナル型になります。アンラップするまで String としては使えないため、コンパイラが nil の場合の処理を強制します。
let input = "42"
let number: Int? = Int(input) // nil if input is not a number
if let number { // unwrap: runs only when not nil
print("got \(number)") // got 42
}
func firstWord(_ text: String) -> String? {
text.split(separator: " ").first.map(String.init)
}
guard let word = firstWord("hello world") else {
fatalError("no words")
}
print(word) // hello
print(firstWord("")?.uppercased() ?? "none") // noneif let と guard let は安全にアンラップし、?.(オプショナルチェーン)は値がある場合にだけメソッドを呼び出し、?? はデフォルト値を与えます。強制アンラップ value! は値が nil のときにクラッシュするので、あまり使わないようにしましょう。省略形の if let number にはSwift 5.7以降が必要です。
構造体、クラス、列挙型、プロトコル
構造体と列挙型は値型で、クラスは継承を持つ参照型です。Swiftのコードでは、クラスの階層よりも、構造体とプロトコル(インターフェース)が好まれます。
protocol Shape {
func area() -> Double
}
struct Rect: Shape {
var width: Double
var height: Double
func area() -> Double { width * height }
}
enum Circle: Shape {
case unit
case radius(Double)
func area() -> Double {
switch self {
case .unit: return Double.pi
case .radius(let r): return Double.pi * r * r
}
}
}
let shapes: [any Shape] = [Rect(width: 2, height: 3), Circle.radius(1)]
let total = shapes.reduce(0) { $0 + $1.area() }
print((total * 100).rounded() / 100) // 9.14構造体には、メンバーワイズイニシャライザ(Rect(width:height:))が自動的に用意されます。列挙型のケースは、.radius(Double) のように関連値を持てます。
エラー処理
失敗しうる関数には throws を付けます。呼び出し側は、do/catch ブロックの中で try を使うか、try? でエラーを nil に変換します。
enum AgeError: Error {
case notANumber(String)
case negative
}
func parseAge(_ text: String) throws -> Int {
guard let age = Int(text) else { throw AgeError.notANumber(text) }
guard age >= 0 else { throw AgeError.negative }
return age
}
do {
print(try parseAge("41")) // 41
print(try parseAge("abc"))
} catch AgeError.notANumber(let text) {
print("not a number: \(text)") // not a number: abc
} catch {
print("other error: \(error)")
}
let maybe = try? parseAge("-3") // nil
print(maybe as Any) // nil小さな完成プログラム:単語の出現頻度
import Foundation
let args = CommandLine.arguments
guard args.count == 2 else {
print("usage: swift words.swift FILE")
exit(1)
}
do {
let text = try String(contentsOfFile: args[1], encoding: .utf8).lowercased()
let words = text.split { !$0.isLetter && $0 != "'" }
var counts: [Substring: Int] = [:]
for word in words {
counts[word, default: 0] += 1
}
for (word, n) in counts.sorted(by: { $0.value > $1.value }).prefix(5) {
print(String(n).padding(toLength: 6, withPad: " ", startingAt: 0) + word)
}
} catch {
print("cannot read \(args[1]): \(error.localizedDescription)")
exit(1)
}swift words.swift notes.txt で実行します。Foundation はファイルの読み込みや文字列のヘルパーを提供し、Appleプラットフォームと、LinuxおよびWindowsのツールチェーンで利用できます。
初心者がよくやる間違い
letの定数や、letの構造体のプロパティを変更しようとする。値を変更する必要があるならvarを使います。- 構造体がオブジェクトのように共有されると期待する。コピーを変更しても元は変わりません。同一性を共有したいならクラスを使います。
s[0]のように、Stringを整数でインデックス指定する。s.first、s.prefix(3)、String.Indexの値を使います。IntとDoubleを変換せずに算術演算で混ぜる。これはコンパイルエラーです。- throwする呼び出しの前に
tryを付け忘れる、またはエラー時にクラッシュするtry!を使う。
次のステップ
docs.swift.orgの公式ガイド兼リファレンス「The Swift Programming Language」と、swift.orgのドキュメントハブを読みましょう。アプリ開発では、XcodeでAppleのSwiftUIチュートリアルに沿って進めます。その後、Swiftの並行処理(async/await とアクター)、ジェネリクス、依存関係を管理するSwift Package Managerを学びます。
よくある質問
SwiftはAppleのプラットフォーム専用ですか?
いいえ。Swiftはオープンソースで、LinuxやWindowsでも動作し、サーバーサイドのコードやツールにも使われます。ただし、SwiftUIやUIKitといったアプリのフレームワークはApple専用です。
SwiftとObjective-Cのどちらを学ぶべきですか?
Swiftを学びましょう。新しいアプリにAppleが推奨している言語で、必要なときには既存のObjective-Cのコードも呼び出せます。
Swiftの構造体とクラスの違いは何ですか?
構造体は値型で、代入や受け渡しのときにコピーされます。クラスは参照型なので、すべての変数が1つのインスタンスを共有します。クラスは継承とデイニシャライザもサポートします。
型の後ろの疑問符は何を意味しますか?
Int? はオプショナルで、Int か nil のどちらかを保持します。値を使う前に、たとえば if let でアンラップする必要があります。