2017-01-08 13 views
5

Oto przykład zabaw:Jak wywołać bardziej konkretny sposób przeciążenia

protocol P { 
    associatedtype T 
    func getValue() -> T 
} 

class Foo: P { 
    func getValue() -> String { 
     return "hello" 
    } 
} 

class Bar { 
    func test<T: P>(_ o: T) { 
     print("Generic", o.getValue()) 
    } 

    func test(_ o: Any) { 
     print("Any") 
    } 
} 

let foo = Foo() 
let bar = Bar() 
bar.test(foo) 

This wyjścia: Any.

Po usunięciu dowolnej wersji test zostanie wywołana metoda ogólna. Klasa Foo jest zgodna z protokołem P, dlaczego Swift nie wybiera metody ogólnej, ponieważ jest bardziej szczegółowy? Czy istnieje sposób na wywołanie tego ogólnego?

+0

Cóż, najprostszym rozwiązaniem byłoby nadanie 'Any'' testowi (_ :) 'generic - np.' Func test (_ o: T) '(nie jestem pewien, czy to bezpośrednio odpowiada na twoje pytanie). – Hamish

+0

Ogólna metoda nie jest w tym przypadku bardziej szczegółowa. Argument do 'test (_ o: Any)' jest jednym z _concrete type_ of "Any" (nawet jeśli sam typ jest protokołem), który może skutecznie opakować instancję 'Foo' jako jej argument. Każdy konkretny typ będzie bardziej szczegółowy niż typowy, a pierwszy będzie miał pierwszeństwo w rozdzielczości przeciążania, wywołując 'bar.test (...)'. Powinieneś zasadniczo unikać używania 'Any' jako konkretnego typu, a lepszym podejściem będzie subst. z nieskrępowanym generycznym opisanym przez @Hamish powyżej (w takim przypadku ograniczony typic będzie bardziej szczegółowy). – dfri

Odpowiedz

2

Z tego, co rozumiem, kompilator zawsze będzie faworyzował jawnie wpisany parametr nad typowym przy wykonywaniu przeciążenia. Zatem w rozdzielczości pomiędzy test<T : P>(_ o: T) i test(_ o: Any) - ten drugi będzie preferowany, ponieważ ma jawny (choć abstrakcyjny) typ parametru, podczas gdy pierwszy jest jedynie symbolem zastępczym.

Dlatego jeśli zrobisz drugiego przeciążenie rodzajowe, a także, kompilator będzie teraz faworyzować pierwszy przeciążenie, jak oboje nie mają wyraźnie wpisane parametry, ale pierwszy przeciążenie jest mocniej ograniczana:

class Bar { 
    func test<T: P>(_ o: T) { 
     print("Generic", o.getValue()) 
    } 

    func test<T>(_ o: T) { 
     print("Any") 
    } 
} 

let foo = Foo() 
let bar = Bar() 
bar.test(foo) // Generic hello 

Utrzymanie przeciążeń jak jest typu odlewów w celu disambiguate również wydaje się być dobrym rozwiązaniem:

class Bar { 
    func test<T: P>(_ o: T) { 
     print("Generic", o.getValue()) 
    } 

    func test(_ o: Any) { 
     print("Any") 
    } 
} 

let foo = Foo() 
let bar = Bar() 
(bar.test as (Foo) -> Void)(foo) // Generic hello 

Choć gorąco polecam pierwsze podejście, ponieważ pozwala rozumowi lepiej o co przeciążać wola być wybranym (rodzajowy s powinno być również preferowane w ogólności w stosunku do parametrów określonych protokołem, gdzie to możliwe, due to the performance benefits of specialisation).

+0

Uważam, że protokoły jako typy zazwyczaj nie są określane jako abstrakcyjne, lecz raczej nietypowe. Możliwe jest uniknięcie tego pierwszego, ponieważ możemy faktycznie mieć wystąpienia tego typu (nie tylko używając ich jako generycznych typów). – dfri

+0

@dfri Huh, zawsze określałem je jako abstrakcyjne (będące antonimem konkretu) - chociaż chciałbym dokonać niewielkiego rozróżnienia między "posiadaniem instancji tego typu" i "posiadaniem instancji wpisanej w ten sposób". Nie możesz mieć instancji typów protokołów, możesz mieć tylko instancje konkretnych typów, wpisywane jako typy protokołów. Z pewnością jest to interesująca kwestia, ale zainteresowałby się tym, jaki jest konsensus wspólnotowy w sprawie użycia słowa "streszczenie". – Hamish

+0

Prawda przy różnicowaniu. Uważam, że interesująca dyskusja dotyczy tego, jak (lub czy) chcemy rozróżnić opis abstrakcyjnych typów znaków (np. Rodzajowy typ, 'T', powyżej lub typalia) kontra wystąpienia wpisane jako protokoły (ten drugi bez użycia generycznych lub typaliów/powiązane typy). Zareagowałem na streszczenie, ponieważ nigdy tak naprawdę nie widziałem tego terminu (Swift, w szczególności) dla innych niż pierwszy w szybkich dokumentach, podczas gdy dla tego ostatniego, co najmniej "Any" (typowane) jest opisane po prostu jako niespecyficzny typ w przewodnik językowy.Ale może to ziemniaki i ziemniaki :) – dfri

Powiązane problemy