Menu
Coddy logo textTech

プロトコルの定義

CoddyのSwiftジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 27/57。

プロトコルは、実装を行わずに要件(メソッドとプロパティ)を一覧にします。型はすべての要件を提供することでプロトコルに準拠し、その後、プロトコルが期待されるあらゆる場所で使用できるようになります。

protocol Describable {
    func describe() -> String
}

struct Book: Describable {
    let title: String
    func describe() -> String { "Book: \(title)" }
}

print(Book(title: "Dune").describe())

出力:

Book: Dune

継承とは異なり、プロトコルは構造体、クラス、列挙型のいずれにも同様に機能し、型は複数のプロトコルに準拠できます。プロトコルが示すのは、型が何をできるかだけです。それぞれの型がどのように実現するかを決めます。

protocol Describable {
    func describe() -> String
}

struct Point: Describable {
    var x = 0, y = 0
    func describe() -> String { "(\(x), \(y))" }
}

enum Level: Describable {
    case low, high
    func describe() -> String { self == .low ? "low" : "high" }
}

print(Point(x: 1, y: 2).describe())
print(Level.high.describe())

出力:

(1, 2)
high

プロパティ要件では、プロパティの型と、そのプロパティが読み取り専用({ get })か、書き込みも可能({ get set })かを指定します。{ get }要件は、格納プロパティまたは計算プロパティで満たすことができます。

protocol Named {
    var name: String { get }
}

struct User: Named {
    let name: String
}

struct Planet: Named {
    var number: Int
    var name: String { "Planet \(number)" }
}

print(User(name: "ada").name)
print(Planet(number: 3).name)

出力:

ada
Planet 3

ある型が準拠を宣言しているにもかかわらず要件を満たしていない場合、コンパイルできません。コンパイラはすべての準拠をチェックするため、プロトコルを使用するコードはその準拠を信頼できます:

protocol Priced {
    var price: Int { get }
    func discounted(by percent: Int) -> Int
}

// struct Ticket: Priced { var price = 10 }
// error: 型 'Ticket' はプロトコル 'Priced' に準拠していません
challenge icon

チャレンジ

簡単

読み取り専用プロパティ name(String)と、Doubleを返すメソッド area() を持つプロトコル Shape を宣言してください。構造体 Rectangle(width、height)と Circle(radius、数値を簡単にするため π には 3.0 を使用)をそれに準拠させ、名前をそれぞれ rectangle と circle にしてください。

提供されたコードは、r,3,4 または c,2 の行を読み取り、対応する図形を作成して rectangle: 12.0 を出力します。

コードは Shape.swift、Rectangle.swift、Circle.swift に記述してください。main.swift には提供された入力/出力コードが含まれており、編集できません。

自分で試してみよう

// 提供された入出力コード: そのままにしておく
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
    let p = line.split(separator: ",").map(String.init)
    if p[0] == "r" {
        let s = Rectangle(width: Double(p[1])!, height: Double(p[2])!)
        print("\(s.name): \(s.area())")
    } else {
        let s = Circle(radius: Double(p[1])!)
        print("\(s.name): \(s.area())")
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Swiftプレイグラウンド