Почему расширения с соответствиями протоколов не могут иметь определенный уровень доступа?

Предположим, у нас есть следующий пример кода:

protocol MyProtocol {
    func someFunction()
}

public class MyClass {

}

public extension MyClass: MyProtocol {
    func someFunction() {
        print("hello")
    }
}

Компиляция кода выше дает следующую ошибку:

Ошибка: модификатор 'public' нельзя использовать с расширениями, которые объявляют о соответствии протокола

То же самое происходит, если я отмечаю расширение как private, Кажется, что вы не можете установить уровень доступа для расширения, соответствующего протоколу, независимо от того, какой уровень доступа установлен. Даже установив объявление протокола на public или же private не удаляет ошибку.

Вопрос

В чем причина того, что Swift ограничивает уровень доступа к расширению таким образом, если он соответствует протоколу? Если соответствие протокола применяется на уровне класса, такого ограничения нет.

Если я подчиняюсь компилятору и удаляю private/public обозначение, каков уровень доступа someFunction()?

extension MyClass: MyProtocol {
    func someFunction() {
        print("hello")
    }
}

Я полагаю, что в этом случае это будет следовать оригинальной MyClass реализация и быть public но я не уверен.

Есть ли такое поведение, потому что соответствие протокола в расширении означает, что весь класс соответствует протоколу, и, следовательно, избыточно повторно указывать уровень доступа в расширении?

3 ответа

Решение

Это потому, что невозможно соответствовать протоколу на любом уровне доступа, кроме уровня доступа самого протокола. Другими словами, если у вас есть public протокол, вы не можете иметь private соответствие этому. Это отчасти потому, что соответствие протокола - это то, к чему можно обратиться во время выполнения (и, следовательно, оно не может отличаться в зависимости от того, в каком модуле вы находитесь, или для реализации дважды в разных файлах / модулях), и отчасти потому, что это будет просто странно, если тип соответствует протоколу в одном файле и не соответствует этому протоколу при использовании в других файлах.

Что касается вашего вопроса об уровне доступа someFunction, он следует тем же правилам, что и любая другая функция. То есть по умолчанию internal, если у самого типа нет более низкого уровня доступа. Так что в вашем случае, если MyClass а также MyProtocol оба publicвы можете ожидать ошибки компилятора, говорящей вам, что someFunction() должен быть отмечен public также. Но так как это выглядит MyProtocol на самом деле internal, пропуская любой модификатор доступа работает как someFunction() по умолчанию internal,

Частное соответствие может нарушать принцип замещения Лискова

Цитируя аннотацию на форуме Apple Devloper, ответьте на аналогичный вопрос:

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

Например, у вас есть класс, который в частном порядке соответствует протоколу и реализует все его методы. Позже появляется подкласс, который хочет сделать то же самое, но хочет реализовать только требуемые методы (поскольку необязательные не реализуемые могут обеспечить поведение по умолчанию, которое подкласс хочет). Но теперь у вас есть 2 проблемы:

1) У объекта, ожидающего реализацию этого протокола, возможно, есть 2 потребителя протокола на одном и том же объекте. Это приводит к тому, что оба объекта должны быть защищены от непредвиденных вызовов. Или нет, так как из-за частного соответствия подкласс не может вызвать super для разрешения неожиданных вызовов.

2) У подкласса нет способа получить желаемое поведение без изменения протокола, так как реализация суперкласса также не может быть удалена без влияния на его поведение.

Источник: ссылка на ветку форума Apple Developer

Если я подчиняюсь компилятору и удаляю частное / публичное обозначение, каков уровень доступа someFunction()?

Что бы вы ни говорили, это так. Ничто не мешает вам отметить уровень доступа someFunction(), Но в этом случае вы не можете пометить его как privateпотому что уровень доступа MyProtocol internal,

Поэтому по умолчанию internal в вашем коде. Ничего не бывает public по умолчанию; public это всегда явно обозначенное обозначение.

Другие вопросы по тегам