2011-06-21 16 views
7

muszę zastąpić następującą metodę Javy w klasie Scala:Scala: Zastępowanie Generic Java metoda, która zwraca null

public class Test<T> { 
    public T test(T o, boolean x) { 
     if (x) { 
      return o; 
     } 
     return null; 
    } 
} 

z następującym podejściu (w Scala), kompilator narzeka: „Wyrażenie typu Null nie jest zgodny z oczekiwanym typu T ":

class Test2[T] extends Test[T] { 
    override def test(o: T, x: Boolean): T = { 
    if (x) { 
     return o 
    } 
    return null 
    } 
} 

próbowałem również zdefiniować Option[T] jako wartość zwracana, ale potem znowu, kompilator narzeka, że ​​podpisy metoda nie będzie pasować.

Każdy pomysł? - Dzięki!


Edit:

sugestia Daniela działa na problem jako Cytat; Jednak moja rzeczywisty Problem niestety nadal różni się nieznacznie (o parametr typu rodzajowego w metodzie nie klasy, definicja) (przepraszam):

Java:

public class Test { 
    public <T> T test(T o, boolean x) { 
     if (x) { 
      return o; 
     } 
     return null; 
    } 
} 

Scala:

class Test2 extends Test { 
    override def test[T >: Null](o: T, x: Boolean): T = { 
    if (x) { 
     return o 
    } 
    return null 
    } 
} 

Kompilacja ponownie kończy się niepowodzeniem z błędem, "Wyrażenie typu Null nie jest zgodne z oczekiwanym typem T".
(wierzę, że to dlatego, że override nie obejmuje żadnych możliwości - czyli coś typu Nothing mogłyby zostać przekazane do Test.test(..) - Cóż, to może ;-))

Co robi praca jest rzucanie RuntimeException zamiast wrócić null jak zasugerował Ricky; niemniej jednak będę wdzięczny za dalsze uwagi.

Dzięki!

Odpowiedz

12

Trzeba to:

class Test2[T >: Null] extends Test[T] { 

Problemem jest to, że nie może być Nothingnull, i jako podtyp wszystkiego, jest to ważna wartość T. Więc musisz określić Null jako dolną granicę.

EDIT

Niestety, nie ma dobry sposób wokół rzeczywistego problemu. W takim przypadku musisz napisać null.asInstanceOf[T] i zostaw to.

I, tak, możesz można nazwać go z nie-null typu. Spróbuj tego, na przykład:

object Test3 { 
    val test = new Test(); 
    val x: Int = test.test(5, false); 
} 
+0

To idealne rozwiązanie problemu, który został pierwotnie opublikowany; jednak musiałem się przekonać, że faktyczny problem nieco się różni. - Zaznaczę to jako rozwiązanie, jeśli nie powinno być dokładniejszej odpowiedzi, ale czy mógłbyś jeszcze raz spojrzeć na - teraz edytowane - pytanie. - Dziękuję bardzo. – robbbert

+0

Dzięki, dobrze zrobione. - Oba rozwiązania działają (drugi z użyciem parametru "[T]" jako typu), chociaż jeszcze nie w pełni rozumiem problem ... – robbbert

+0

@robbbert Wyszukaj informacje na temat 'Nothing' i' Null', aby lepiej to zrozumieć . –

6

T nie jest ograniczona, dzięki czemu może być dowolnego typu, w tym Int, Double, Float lub innych podtypów AnyVal, które nie mogą być null.

Prawdopodobnie chcesz klasę Test2[T <: AnyRef] zamiast klasy Test[T], oświadczając, że T jest każdy rodzaj czyli AnyRef (zasadniczo java.lang.Object) lub jakiejkolwiek jego podtyp.

Ogólnie rzecz biorąc, spróbuj zwrócić coś bardziej użytecznego niż wartość NULL lub wyślij wyjątek. Mogą być przypadki, w których musisz to zrobić z powodu jakiegoś API strony trzeciej, ale jeśli tak nie jest, sprawdź, czy jest lepszy sposób. null nie pojawia się w typie metody, podczas gdy na przykład Option.

+0

to, co myślę, ale ' def z [T <: AnyRef]: T = null' nadal się nie kompiluje. – kassens

+0

'class Test2 [T <: AnyRef] extends Test [T]' powinien skompilować dobrze –

+0

@oxbow_lakes Nie, nie ma, odpowiedź Daniela jest poprawna. – kassens

0

Czy uważane za pomocą opcji zamiast następujące zadziała:

class Test{ 
    def test[T] (value:T,flag :Boolean) :Option[T] = { 
    if (flag){ 
     Some(value) 
    }else{ 
     None 
    } 
    } 
} 

To pomoże odróżnić sytuacje jak test(null,true) i test(null,false)

+0

Dziękuję, ale (jak wspomniano w pytaniu oryginalnym), że jest to inny podpis metody niż metoda zastąpiona. – robbbert

Powiązane problemy