Od Scali 2.7.2 istnieje coś, co nazywa Manifest
się obejściem wymazywania typu Java. Ale jak Manifest
dokładnie działa i dlaczego / kiedy należy go użyć?
Post na blogu Manifests: Reified Types autorstwa Jorge Ortiza wyjaśnia niektóre z nich, ale nie wyjaśnia, jak używać go razem z ograniczeniami kontekstu .
Co to jest ClassManifest
, jaka jest różnica Manifest
?
Mam kod (będący częścią większego programu, nie można go tu łatwo dołączyć), który zawiera ostrzeżenia dotyczące usuwania typów; Podejrzewam, że mogę je rozwiązać za pomocą manifestów, ale nie wiem dokładnie, jak.
Odpowiedzi:
Kompilator zna więcej informacji o typach niż środowisko wykonawcze maszyny JVM może z łatwością przedstawić. Manifest to sposób, w jaki kompilator wysyła do kodu w czasie wykonywania komunikat międzywymiarowy dotyczący utraconych informacji o typie.
Jest to podobne do tego, jak Kleptonianie pozostawili zakodowane wiadomości w zapisach kopalnych i „śmieciowym” DNA ludzi. Ze względu na ograniczenia prędkości światła i pola rezonansu grawitacyjnego nie mogą się bezpośrednio komunikować. Ale jeśli wiesz, jak dostroić się do ich sygnału, możesz skorzystać na sposoby, których nie możesz sobie wyobrazić, decydując o tym, co zjeść na lunch lub w którą lotto zagrać.
Nie jest jasne, czy Manifest przyniósłby korzyści dla błędów, które widzisz, nie znając więcej szczegółów.
Jednym z typowych zastosowań manifestów jest to, że kod zachowuje się inaczej w zależności od statycznego typu kolekcji. Na przykład, co by było, gdybyś chciał traktować List [String] inaczej niż inne typy List:
def foo[T](x: List[T])(implicit m: Manifest[T]) = { if (m <:< manifest[String]) println("Hey, this list is full of strings") else println("Non-stringy list") } foo(List("one", "two")) // Hey, this list is full of strings foo(List(1, 2)) // Non-stringy list foo(List("one", 2)) // Non-stringy list
Oparte na refleksji rozwiązanie tego problemu wymagałoby prawdopodobnie sprawdzenia każdego elementu listy.
Wiązanie kontekstu wydaje się najbardziej odpowiednie do używania klas typu w scali i jest dobrze wyjaśnione tutaj przez Debasish Ghosh: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html
Ograniczenia kontekstu mogą również sprawić, że sygnatury metod będą bardziej czytelne. Na przykład powyższa funkcja może zostać ponownie napisana przy użyciu ograniczeń kontekstu, takich jak:
def foo[T: Manifest](x: List[T]) = { if (manifest[T] <:< manifest[String]) println("Hey, this list is full of strings") else println("Non-stringy list") }
źródło
Nie jest to pełna odpowiedź, ale jeśli chodzi o różnicę między
Manifest
iClassManifest
, możesz znaleźć przykład w artykule Scala 2.8Array
:Przykład:
def tabulate[T](len:Int, f:Int=>T)(implicit m:ClassManifest[T]) = { val xs = new Array[T](len) for (i <- 0 until len) xs(i) = f(i) xs }
(Zobacz to pytanie SO dla ilustracji )
def tabulate[T: ClassManifest](len:Int, f:Int=>T) = { val xs = new Array[T](len) for (i <- 0 until len) xs(i) = f(i) xs }
źródło
Manifest miał na celu reifikację typów ogólnych, które są usuwane z typów w celu uruchomienia na maszynie JVM (która nie obsługuje typów ogólnych). Miały jednak poważne problemy: były zbyt uproszczone i nie były w stanie w pełni obsługiwać systemu typów Scali. W związku z tym zostały one przestarzałe w Scali 2.10 i zostały zastąpione przez
TypeTag
s (które są zasadniczo tym, czego sam kompilator Scali używa do reprezentowania typów, a zatem w pełni obsługuje typy Scala). Aby uzyskać więcej informacji na temat różnicy, zobacz:Innymi słowy
Przed 2013-01-04, kiedy została wydana Scala 2.10 .
źródło
Sprawdźmy też
manifest
wscala
sources (Manifest.scala
), widzimy:Manifest.scala: def manifest[T](implicit m: Manifest[T]) = m
A więc jeśli chodzi o następujący przykładowy kod:
def foo[A](somelist: List[A])(implicit m: Manifest[A]): String = { if (m <:< manifest[String]) { "its a string" } else { "its not a string" } }
widzimy, że
manifest
function
wyszukuje niejawny,m: Manifest[T]
który spełniatype parameter
podane przez Ciebie w naszym przykładowym kodziemanifest[String]
. Więc kiedy zadzwonisz do czegoś takiego:if (m <:< manifest[String]) {
sprawdzasz, czy bieżący,
implicit m
który zdefiniowałeś w swojej funkcji, jest typu,manifest[String]
a ponieważmanifest
jest funkcją typumanifest[T]
, szukałby określonegomanifest[String]
i znalazłby, czy istnieje taki niejawny.źródło