2013-08-28 20 views
6

Kompilator Scala ma -Xcheck-null, który próbuje sprawdzić, czy istnieje potencjalny dereferencja wskaźnika zerowego w środowisku wykonawczym.Wywołanie metody Mark, która zawsze zwraca wynik niepusty null

To dla mnie ok, ale mam zbyt wiele fałszywych alarmów, czyli załóżmy zdefiniować Rejestrator:

private final val LOGGER: Logger = LoggerFactory.getLogger(classOf[GenericRestImpl]) 

metody getLogger nigdy nie powraca null. Jak mogę przekazać tę wiedzę do kompilatora, aby nie narzekać?

[WARNING] TestImpl.scala:31: warning: potential null pointer dereference: LOGGER.debug 
[WARNING]  LOGGER.debug("Using {} for sort", sortParam) 

Kiedy tworzę nową instancję mogę oznaczyć je NotNull cechy:

return new Foo() with NotNull. 

to jest OK, ale co zrobić z obiektami wrócił z innymi metodami? Zwłaszcza jeśli pochodzi z biblioteki innej firmy? Nie podoba mi się pomysł, aby oznaczyć wszystkie moje zmienne jako opcjonalne, ponieważ zwiększy to obciążenie. Również nie lubię pomysł, aby utworzyć niejawne konwersje (bo będzie to wymagało dodatkowej klasy dla każdej klasy, że chcesz oznaczyć jako NotNull.

Ja również sprawdzone pytanie Library support for Scala's NotNull trait ale to nie pomogło rozwiązać mój problem.

+0

Dobrze rozumiesz, cecha NotNull jest tylko znacznikiem. Nie robi nic więcej. – Jatin

Odpowiedz

5

Jak wspomina Jatin, NotNull jest tylko markerem lub tag, dzięki czemu można używać NotNull oznaczyć coś. Sztuką aby to zrobić jest wymuszanie oddać swój typ bazowy with NotNull.

więc można napisać coś takiego to "notnull".asInstanceOf[String with NotNull]. To bezpieczne rzucenie, jeśli masz pewność, że nigdy nie ma wartości NULL

W aktualnej przykład, można więc napisać:

private final val LOGGER: Logger with NotNull = 
    LoggerFactory.getLogger(classOf[GenericRestImpl]).asInstanceOf[Logger with NotNull] 

Choć nie ma potrzeby tworzenia nowych typów na to, że jest to nieco kłopotliwe, jeśli masz to zrobić dużo, więc można korzystać z niektórych małe utils uproszczenie/wyjaśnienie zapisu:

type NeverNull[T] = T with NotNull 
def neverNull[A](a: A): NeverNull[A] = a.asInstanceOf[A with NotNull] 

NeverNull tylko aliasem dla każdego typu T oznakowanego z NotNull i neverNull jest trochę wrapper oznaczyć dowolną istniejącą wartość typu A jako nigdy zerowa.

Następnie można go używać jako:

private final val LOGGER: NeverNull[Logger] = neverNull { 
     LoggerFactory.getLogger(classOf[GenericRestImpl]) 
} 

Można nawet zrobić to niejawna konwersja, jeśli jesteś pewien, co robisz:

implicit def neverNull[A](a: A): NeverNull[A] = a.asInstanceOf[A with NotNull] 

private final val LOGGER: NeverNull[Logger] = LoggerFactory.getLogger(classOf[GenericRestImpl]) 

Zauważ, że NeverNull[Logger] jest nadal a Logger, aby można było wywołać na nim dowolną metodę tej klasy lub przekazać ją do funkcji, które przyjmują jako parametr wartość Logger.

Ten rodzaj konstrukcji jest nazywany unboxed określili rodzaj i jest bardzo przydatna, zobaczyć inne aplikacje i dyskusji here i here.

Powiązane problemy