Istnieje pewne wytłumaczenie tutaj
Typy i obiekty mogą mieć również nazwy symboliczne; w szczególności powinno być wspomniał, że dla typów z dwoma parametrami typu można zapisać nazwę między parametrami, aby np.
Int <:< Any
jest taki sam jak<:<[Int, Any]
.
Ale nadal nie mogłem tego zdobyć, doceniłbym, gdyby ktoś mógł podać wyjaśnienie na przykładzie.
Odpowiedzi:
1 dla odpowiedzi № 1To jest klasa zdefiniowana w obiekcie Predef
:
abstract class <:<[-From, +To] extends Function1[From, To]
Wystąpienie
A <:< B
świadczą o tymA
jest podtypemB
.
To, że nazwa klasy ma charakter symboliczny, nie ma szczególnych konsekwencji, mogło zostać nazwane IsSubType[From, To]
znany jako From IsSubType To
.
Dostajesz "dowody" instancji tej klasy w drodze Predef.$conforms
:
implicit def $conforms[A]: <:<[A, A]
Przypadku użycia tego jest, gdy masz typ A
ale chcesz operować na podtypie B <: A
. Następnie możesz po prostu poprosić o ten domniemany dowód:
trait Foo[A] {
def x: A
// def fails: Int = x * x -- not possible, we don"t know that A is an Int
def succeeds(implicit ev: A <:< Int): Int = x * x
}
Z miejsca użycia kompilator pozwala nam tylko zadzwonić succeeds
gdyby A <: Int
, ponieważ w przeciwnym razie nie bylibyśmy w stanie uzyskać ev
parametr. Niejawne wyszukiwanie działa z powodu sposobu, w jaki kompilator może wywnioskować górne granice poszukiwanego typu w oparciu o wariancję parametrów typu From
i To
z <:<
.
(Oczywiście Int
jest ostatecznym typem, więc mogliśmy poprosić o równość A =:= Int
, to jest po prostu prosty przykład.)