2014-07-15 15 views
5

Czy możliwe jest dynamiczne wymuszenie boksowania runtime w scala? Chciałbym funkcję:Uniwersalny/ogólny boks od Any do AnyRef

def box(value :Any) :AnyRef 

lub

def box[T](value :T) :AnyRef 

mam rodzajowe klasy, które mogą być programowane z AnyVals ale trzeba przekazać je do metod dziedzictwem java akceptujących zbiory przedmiotów. Oczywiście sam mógłbym to zaimplementować za pomocą dopasowywania wzorców, ale trochę denerwujące jest to, że muszę to robić raz po raz, i nie działałoby to dla klas wartości użytkownika.

Edit

Odpowiedź okazała się tak prosta, jak zaskakujące. Czy mogę to zrobić poprzez odbicie? Zakładamy

class Box[T :TypeTag](private var value :T) { 
    def get :T = value 
    def set(o :Any) { 
     ... 
    } 
} 

Chciałbym zrobić bezpieczny zestaw, sprawdzając w czasie wykonywania, jeśli o to podklasą T tak:

runtimeMirror(getClass.getClassLoader).classSymbol(o.getClass).toType <:< typeOf[T] 

Niestety typeof [T] na polu [Long] będzie be prymitywny, a następujące sprawdzanie nie powiedzie się na java.lang.Long, który jest typem środowiska wykonawczego elementów Seq [Long] na przykład. Podsumowując, podczas używania generycznych z AnyValami, kompilator czasami je zapakowuje, sprawiając, że sprawdzenie klasy runtime będzie nieprzewidywalne.

+0

Twoja dodana część nie wygląda na boks z "Any" na "AnyRef". (Wygląda na to, że ma to coś wspólnego z rozpakowywaniem?) Co z tym, że jest to drugie, osobne pytanie? –

Odpowiedz

4

Wystarczy rzucić do AnyRef z asInstanceOf i Scala będzie przekształcić go w AnyRef:

scala> val x = 13 
x: Int = 13 

scala> val xBoxed = x.asInstanceOf[AnyRef] 
xBoxed: AnyRef = 13 

scala> xBoxed.getClass() 
res0: Class[_ <: AnyRef] = class java.lang.Integer 

Dla klas wartości, to pole to w instancji klasy wartości, zamiast klasy Javy. Możesz użyć ogólnej cechy, aby móc uzyskać wersje pudełkowe Java z twoich klas wartości, bez użycia odbicia. Na przykład:

trait ValueClass[T] extends Any { 
    def value: T 
    def javaBoxed: AnyRef = value.asInstanceOf[AnyRef] 
} 

case class MyInt(value: Int) extends AnyVal with ValueClass[Int] 

case class MyReal(asDouble: Double) extends AnyVal with ValueClass[Double] { 
    def value = asDouble 
} 

Wymaga to jednak połączenia cechy w wszystkie klasy wartości. Dla klas wartości, które rozciągają Product, jak wszystkie klasy przypadków zrobić, nie ma szybszego sposobu korzystania productElement:

def javaBox(x: Product): AnyRef = { 
    if (x.productArity == 1) x.productElement(0).asInstanceOf[AnyRef] 
    else x.asInstanceOf[AnyRef] // or throw an exception if you prefer 
} 

Niestety, wygląda mi na to obu metod (cecha mix-in i Product) przyczyna Scala zrobić swój boks , co oznacza, że ​​po wywołaniu wartości unboxed, wartość przechodzi z unboxed → Scala boxed → unboxed → Java boxed, zamiast prosto do wartości boxed Java.

+0

Niesamowite, dzięki! Jest to dość zabawne, ponieważ '42.asInstanceOf [AnyVal]' spowoduje wygenerowanie ostrzeżenia kompilatora mówiącego, że zawsze jest ono fałszywe, ale będzie miało wartość "true". Wydaje się również, że nie działa w przypadku klas wartości użytkownika. Dodałem pytanie dodatkowe do pierwotnego pytania o dodatkowy kredyt. – Turin