При создании быстрого протокола необходимо ли объявлять переменные или функции в своем теле, если стандартные реализации поставляются через расширение? [Дубликат]

Кажется, что вы действительно хотели написать:

assert item.price == 19.99

(Конечно, сравнение float для равенства или использование float для цен - это плохая идея , поэтому вы напишете assert item.price == Decimal(19.99) или какой-нибудь цифровой класс, который вы использовали для цены.)

Вы также можете использовать платформу тестирования, например py.test , чтобы получить дополнительную информацию о сбоях утверждает в ваших тестах.

5
задан Aaron Rasmussen 13 January 2016 в 23:01
поделиться

1 ответ

Объявление функции в протоколе дает указание компилятору использовать динамическую отправку при вызове функции, поскольку компилятор ожидает, что типы, реализующие протокол, предоставят реализацию для этой функции. Это называется method requirement. Если тип не определяет метод, то среда выполнения разрешает вызов метода методу, объявленному в расширении протокола.

Объявление функции только в расширении протокола сообщает компилятору, что он не нужен использовать динамическую отправку и использовать статическую диспетчеризацию, которая выполняется быстрее, но не очень хорошо работает с полиморфизмом, поскольку будет реализована реализация расширения протокола.

Чтобы проиллюстрировать выше, рассмотрим следующий код:

protocol Shape {
    func draw()
}

extension Shape {
    func draw(){
        print("This is a Shape")
    }
}

struct Circle: Shape {
    func draw() {
        print("This is a Circle")
    }
}

struct Square: Shape {
    func draw() {
        print("This is a Square")
    }
}

let shapes: [Shape] = [Circle(), Square()]

for shape in shapes {
    shape.draw()
}

Вышеприведенный код будет иметь выход

This is a Circle 
This is a Square

Это связано с тем, что draw() является method requirement, что означает, что при вызове draw() , среда выполнения будет искать реализацию draw () в действительном типе элемента, в данном случае внутри Circle и Square.

Теперь, если мы не объявим draw как требование метода, что означает, что мы не упоминаем его в объявлении протокола

protocol Shape {
}

. Затем компилятор больше не будет использовать динамическую отправку и перейдет прямо к реализации, определенной в расширение протокола. Таким образом, код будет печатать:

This is a Shape
This is a Shape

Подробнее, если мы сбрасываем листинг элемента массива на тип, который, как мы ожидаем, он будет, мы получим статическое связывание назад. Это напечатает This is a Circle

if let circle = shapes[0] as? Circle {
    circle.draw()
}

, потому что компилятор теперь может сказать, что первый элемент из shapes является Circle, а поскольку Circle имеет метод draw(), он будет вызывать это.

Это способ Swift справиться с абстрактными классами: он дает вам возможность указать, что вы ожидаете от типов, соответствующих этому протоколу, и при этом допускать реализацию по умолчанию этих методов.

4
ответ дан Cristik 31 August 2018 в 23:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: