it-swarm.dev

Dlaczego rozszerzenia o zgodności z protokołem nie mają określonego poziomu dostępu?

Załóżmy, że mamy następujący przykładowy kod:

protocol MyProtocol {
    func someFunction()
}

public class MyClass {

}

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

Kompilacja powyższego kodu daje następujący błąd:

Błąd: modyfikator „public” nie może być używany z rozszerzeniami deklarującymi zgodność z protokołem

To samo dzieje się, gdy zaznaczę rozszerzenie jako privatename__. Wydaje się, że nie można ustawić poziomu dostępu do rozszerzenia zgodnego z protokołem, niezależnie od tego, jaki poziom dostępu jest ustawiony. Nawet ustawienie deklaracji protokołu na publiclub privatenie usuwa błędu.

Pytanie

Jaki jest powód, dla którego Swift ogranicza poziom dostępu do rozszerzenia w ten sposób, jeśli jest zgodny z protokołem? Jeśli zgodność protokołu jest stosowana na poziomie klasy, nie ma takiego ograniczenia.

Jeśli zastosuję się do kompilatora i usunie oznaczenie privatename __/publicname__, jaki jest poziom dostępu funkcji someFunction()?

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

Wyobrażam sobie, że w tym przypadku byłby zgodny z oryginalną implementacją MyClassi byłby publicname__, ale nie jestem pewien.

Czy to zachowanie istnieje, ponieważ zgodność protokołu w rozszerzeniu oznacza, że ​​cała klasa jest zgodna z protokołem, a zatem ponowne określanie poziomu dostępu w rozszerzeniu jest zbędne?

9
Paolo

To dlatego, że niemożliwe jest dostosowanie się do protokołu na dowolnym poziomie dostępu innym niż poziom dostępu samego protokołu. Innymi słowy, jeśli masz protokół public, nie możesz mieć zgodności z private. Jest to częściowo dlatego, że zgodność protokołu jest czymś, o co można zapytać w czasie wykonywania (i dlatego nie może się różnić między modułem, w którym się znajdujesz, lub być zaimplementowanym dwukrotnie w różnych plikach/modułach), a częściowo dlatego, że byłoby po prostu dziwne, gdyby typ zgodny z protokołem w jednym pliku i niezgodny z tym protokołem, gdy jest używany w innych plikach.

Jeśli chodzi o twoje pytanie o poziom dostępu someFunction, stosuje się te same zasady, co w każdej innej funkcji. Oznacza to, że domyślnie jest to internal, chyba że sam typ ma niższy poziom dostępu. Więc w twoim przypadku, jeśli MyClass i MyProtocolpublic, możesz oczekiwać, że otrzymasz błąd kompilatora informujący, że someFunction() musi być również oznaczony public. Ale ponieważ wygląda na to, że MyProtocol jest w rzeczywistości internal, pominięcie jakiegokolwiek modyfikatora dostępu działa jak someFunction() domyślnie na internal.

14
Lily Ballard

Jeśli przestrzegam kompilatora i usuwam oznaczenie prywatne/publiczne, jaki jest poziom dostępu funkcji someFunction()?

Cokolwiek to powiesz. Nic nie stoi na przeszkodzie, aby zaznaczyć poziom dostępu funkcji someFunction(). Ale w tym przypadku nie możesz oznaczyć go jako privatename__, ponieważ poziom dostępu MyProtocol to internalname__.

Domyślnie w kodzie jest internalname__. Domyślnie nic nie jest publicname__; publicjest zawsze jawnym oznaczeniem.

1
matt

Zgodność prywatna może naruszać Zasada substytucji Liskowa

Cytując streszczenie z forum Apple devloper odpowiedz na podobne pytanie:

„Największą rzeczą, jaką zauważyłem w kwestii zgodności prywatnej, szczególnie w klasach, które mają być dalej subklasowane, jest to, że często kończy się to konfliktowymi implementacjami”.

Na przykład masz klasę, która prywatnie odpowiada protokołowi i implementuje wszystkie jego metody. Później pojawia się podklasa i chce zrobić to samo, ale chce tylko zaimplementować wymagane metody (ponieważ opcjonalne, które nie są implementowane, mogą zapewnić pewne domyślne zachowanie, którego chce podklasa). Ale teraz masz 2 problemy:

1) Obiekt oczekujący tej implementacji protokołu może teraz mieć 2 konsumentów protokołu na tym samym obiekcie. Prowadzi to do tego, że oba obiekty muszą chronić się przed nieoczekiwanymi połączeniami. Lub brak, ponieważ ze względu na prywatność, podklasa nie może zadzwonić super, aby rozwiązać nieoczekiwane połączenia.

2) Podklasa nie ma sposobu na zachowanie, którego chce, bez modyfikowania protokołu, ponieważ implementacja superklasy nie może zostać usunięta bez wpływu na jej zachowanie.

Źródło: Link do wątku forum Apple Developer

1
Say2Manuj