Menu
Coddy logo textTech

Определение протоколов

Часть раздела Объектно-ориентированное программирование путешествия по Swift на Coddy. Урок 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: type 'Ticket' does not conform to protocol 'Priced'
challenge icon

Задание

Легко

Объявите протокол Shape со свойством name (String), доступным только для чтения, и методом area(), возвращающим Double. Сделайте так, чтобы структуры 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