Jak badać obiekty / typy / itp. z Scala REPL?
Pracuję ze Scalą już od jakiegoś czasu i napisałem z nią program wiersza 10 000+, ale nadal jestem zdezorientowany przez niektóre wewnętrzne działania. Przyszedłem do Scali z Pythona, po tym, jak już dobrze poznałem Java, C i Lisp, ale mimo to działa powoli, a ogromnym problemem jest frustrująca trudność, którą często spotykam, próbując zbadać wewnętrzne działanie obiektów / typów / klasy / etc. używając Scala REPL w porównaniu z Pythonem. W Pythonie możesz badać dowolny obiektfoo
(typ, obiekt w zmiennej globalnej, funkcja wbudowana itp.) przy użyciufoo
aby zobaczyć, co ta rzecz ocenia,type(foo)
aby pokazać jego typ,dir(foo)
aby powiedzieć, jakie metody możesz wywołać ihelp(foo)
aby uzyskać wbudowaną dokumentację. Możesz nawet robić takie rzeczyhelp("re")
znaleźć dokumentację o nazwie pakieture
(który przechowuje obiekty i metody wyrażenia regularnego), nawet jeśli nie ma z nim skojarzonego obiektu.
W Scali możesz spróbować przeczytać dokumentację online, przejrzeć kod źródłowy w bibliotece itp., Ale często może to być bardzo trudne dla rzeczy, w których nie wiesz, gdzie lub nawet są (i często duży kawałek do odgryzienia, biorąc pod uwagę obszerną hierarchię typów) - rzeczy pływają w różnych miejscach (pakietscala
, Predef
, różne niejawne konwersje, takie jak symbole::
które są prawie niemożliwe dla Google). REPL powinien być sposobem na bezpośrednie odkrywanie, ale w rzeczywistości rzeczy są o wiele bardziej tajemnicze. Powiedz, że widziałem odniesienie dofoo
gdzieś, ale nie mam pojęcia, co to jest. Najwyraźniej nie ma czegoś takiego jak „przewodnik do systematycznego badania Scala za pomocą REPL”, ale to, co połączyłem po wielu próbach i błędach:
foo
jest wartością (która prawdopodobnie obejmuje rzeczy zapisane w zmiennych plus obiekty towarzyszące i inne Scala)object
s), możesz ocenićfoo
bezpośrednio. Powinno to powiedzieć, jaki jest typ i wartość wyniku. Czasami wynik jest pomocny, czasem nie.Jeślifoo
to wartość, której możesz użyć:type foo
uzyskać jego typ. (Niekoniecznie oświecenie.) Jeśli użyjesz tego w wywołaniu funkcji, otrzymasz typ wartości zwracanej, bez wywoływania funkcji.Jeślifoo
to wartość, której możesz użyćfoo.getClass
uzyskać jego klasę. (Często bardziej oświecająca niż poprzednia, ale w jaki sposób klasa obiektu różni się od jej typu?)Dla klasyfoo
, możesz użyćclassOf[foo]
, chociaż nie jest oczywiste, co oznacza wynik.Teoretycznie możesz użyć:javap foo
zdemontować klasę - która powinna być najbardziej użyteczna ze wszystkich, ale dla mnie nie działa całkowicie i jednolicie.Czasami trzeba układać rzeczy z komunikatów o błędach.Przykład użycia awarii:javap
:
scala> :javap List
Failed: Could not find class bytes for 'List'
Przykład oświecającego komunikatu o błędzie:
scala> assert
<console>:8: error: ambiguous reference to overloaded definition,
both method assert in object Predef of type (assertion: Boolean, message: => Any)Unit
and method assert in object Predef of type (assertion: Boolean)Unit
match expected type ?
assert
^
OK, spróbujmy teraz prostego przykładu.
scala> 5
res63: Int = 5
scala> :type 5
Int
scala> 5.getClass
res64: java.lang.Class[Int] = int
Wystarczająco proste ...
Wypróbujmy teraz kilka prawdziwych przypadków, w których nie jest to takie oczywiste:
scala> Predef
res65: type = scala.Predef$@3cd41115
scala> :type Predef
type
scala> Predef.getClass
res66: java.lang.Class[_ <: object Predef] = class scala.Predef$
Co to znaczy? Dlaczego jest typPredef
po prostutype
, podczas gdy klasa jestscala.Predef$
? Rozumiem, że $ to sposób, w jaki obiekty towarzyszące przechodzą na Javę ... ale dokumenty Scala w Google mówią mi o tymPredef
jestobject Predef extends LowPriorityImplicits
- jak mogę to wywnioskować z REPL? A jak mogę sprawdzić, co w niej jest?
OK, spróbujmy czegoś innego:
scala> `::`
res77: collection.immutable.::.type = ::
scala> :type `::`
collection.immutable.::.type
scala> `::`.getClass
res79: java.lang.Class[_ <: object scala.collection.immutable.::] = class scala.collection.immutable.$colon$colon$
scala> classOf[`::`]
<console>:8: error: type :: takes type parameters
classOf[`::`]
^
scala> classOf[`::`[Int]]
res81: java.lang.Class[::[Int]] = class scala.collection.immutable.$colon$colon
OK, to sprawiło, że byłem beznadziejnie zdezorientowany i ostatecznie musiałem przeczytać kod źródłowy, żeby to wszystko zrozumieć.
Moje pytania to:
Jaki jest zalecany najlepszy sposób od prawdziwych ekspertów Scali na używanie REPL do zrozumienia obiektów, klas, metod itp. Scali, a przynajmniej zbadanie ich najlepiej, jak można to zrobić z REPL?Jak mogę uzyskać:javap
pracujesz z REPL dla wbudowanych rzeczy? (Czy nie powinno to działać domyślnie?)Dzięki za wszelkie oświecenie.