2013-03-31 9 views
6

Zawsze rozumiałem argumenty konstruktorów klas przypadków jako definiujące znaki publiczne.Dlaczego pola klasy przypadku Scala nie są publiczne?

Jednak, gdy odbijam pola, metoda isPublic jest fałszywa. Jakieś pomysły, dlaczego?

scala> class Test(val name : String, val num : Int) 
defined class Test 

scala> import scala.reflect.runtime.universe._ 
import scala.reflect.runtime.universe._ 

scala> val tpe = typeOf[Test] 
tpe: reflect.runtime.universe.Type = Test 

scala> def checkValVisibility(t : Type) = { 
    | t.members 
    | .filter(_.isTerm) 
    | .map(_.asTerm) 
    | .filter(_.isVal) 
    | .map(memb => "Val " + memb.name.toString.trim + " is public? " + memb.isPublic) 
    | .mkString("\n") 
    | } 
checkValVisibility: (t: reflect.runtime.universe.Type)String 

scala> checkValVisibility(tpe) 
res2: String = 
Val num is public? false 
Val name is public? false 
+1

Czy Scala nie generuje automatycznie publicznych metod dostępu do prywatnych zmiennych instancji? Nie jestem pewien, czy szczegóły implementacji powinny zostać ujawnione poprzez refleksję, ale być może szukanie w metodach pozwoliłoby ci dalej. – copumpkin

Odpowiedz

11

Powodem jest to, że rzeczywiste wartości, że zapytanie o num i name rzeczywiście są prywatne. W przypadku klas przypadków (i klas z publicznymi parametrami klasy) parametry klasy są implementowane jako prywatne pola z publicznymi akcesoriami (które są generowane automatycznie dla ciebie).

Jeśli chcesz użyć Scala refleksji do uzyskania symbol reprezentujący akcesor publicznego na danym obszarze, można po prostu zrobić:

scala> tpe.member("name": TermName) 
res02: reflect.runtime.universe.Symbol = value name 

Widać, że jest to publiczna accessor jeśli zrobić:

scala> tpe.member("name": TermName).isPublic 
res03: Boolean = true 

scala> tpe.member("name": TermName).isMethod 
res04: Boolean = true 

W Twoim przypadku odfiltrowałeś akcesory, pozostawiając tylko rzeczywiste pola (prywatne). Możesz zmienić swój kod z góry, aby osiągnąć to, co chcesz, zamiast sprawdzając z isAccessor (lub isGetter) zamiast isVal.

scala> def checkValVisibility(t : Type) = { 
    | t.members 
    | .filter(_.isTerm) 
    | .map(_.asTerm) 
    | .filter(_.isAccessor) 
    | .map(memb => "Val " + memb.name.toString.trim + " is public? " + memb.isPublic) 
    | .mkString("\n") 
    | } 
checkValVisibility: (t: reflect.runtime.universe.Type)String 

scala> checkValVisibility(tpe) 
res05: String = 
Val num is public? true 
Val name is public? true 
+0

Jedną rzeczą, którą wczoraj powiedział mi wczoraj Eugene Burmako, jest to, że odbicie Scala próbuje uratować użytkowników przed świadomością "szczegółów implementacji" tego rodzaju. To ma dla mnie sens, że jest zaimplementowany w ten sposób, ale czy jest to właściwy poziom abstrakcji, z którym ma się borykać Scala Reflection? Chociaż prawdopodobnie kod Steve'a Waldmana starał się być zbyt szczegółowy, a łatwych akcesorów, których proponujesz na początku swojej odpowiedzi, robię dokładnie to, co proponuję ... – copumpkin

+0

Dzięki, bardzo wyraźna i kompletna odpowiedź! –

+1

Czy można dojść do wniosku, że vals NIGDY nie są publiczne, a jedynie ich autogeneracja? Nawet w klasach nieprzypadkowych pub vals odzwierciedlają jako niepubliczne, podczas gdy akcesory odzwierciedlają jako publiczne. To trafia na pytanie copumpkina: Czy zastanawiam się nad szczegółami wdrożenia? on val as pvt Pole Java + automatycznie generowany akcesor, a nie natywna konstrukcja Scala? Cieszę się, że mogę żyć w/wyobrażenie, że odzwierciedlenie "vals" to pola leżące u podstaw, że widoczność i dostęp powinny zwisać z dostępu. Ale to może być lepiej udokumentowane. Jeszcze raz dziękuję za pracę i za wspaniałą odpowiedź! –

Powiązane problemy