2013-08-28 5 views
6

Scala компилятор имеет -Xcheck-null, который пытается проверить, есть ли потенциальная развязка нулевого указателя во время выполнения.Метод Mark вызывает, что он всегда возвращает не нулевой результат.

Это нормально для меня, но я получаю слишком много ложных срабатываний, то есть предположим, я определяю регистратор:

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

Метод getLogger никогда не возвращается null. Как передать эти знания компилятору, чтобы он не стал жаловаться?

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

Когда я создаю новый экземпляр можно пометить его NotNull черты:

return new Foo() with NotNull. 

Это нормально, но что делать с объектами возвращаются из других методов? Особенно, если он идет от сторонней библиотеки? Мне не нравится идея отмечать все мои переменные как Необязательные, потому что это добавит слишком много накладных расходов. Кроме того, мне не нравится идея создания неявных преобразований (потому что для каждого класса потребуется дополнительный класс, который я хочу отметить как NotNull.

Я также проверил вопрос Library support for Scala's NotNull trait, но это не помогло решить мою проблему.

+0

Вы правильно понимаете, NotNull trait - это всего лишь маркер. Он ничего не делает. – Jatin

ответ

5

Как отмечает Jatin, NotNull только маркер или метка, так что вы можете использовать NotNull помечать что-нибудь. хитрость, чтобы сделать это, чтобы принуждать бросание ваш базовый тип with NotNull.

таким образом, вы можете написать что-то вроде это "notnull".asInstanceOf[String with NotNull].Это безопасный литой, если вы уверены, что он никогда не был пустым.

В вашем конкретном примере, вы можете таким образом написать:

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

Хотя нет необходимости создавать новые типы для этого, это немного громоздким, если вам нужно сделать, это много, так что вы могли бы использовать некоторые маленькие утилиты для упрощения/уточнения обозначения:

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

NeverNull это просто псевдоним для любого типа T помеченного NotNull и neverNull немного обертки, чтобы пометить любое существующее значение типа A как никогда нуль.

Вы можете использовать его как:

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

Можно даже сделать это неявное преобразование, если вы действительно уверены, что вы делаете:

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

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

Обратите внимание, что NeverNull[Logger] еще a Logger, поэтому вы можете вызвать любой метод этого класса на нем или передать его функциям, которые принимают в качестве параметра a Logger.

Этот вид конструкции называется распакованный тегами типа и очень полезно, увидеть другие приложения и обсуждение here и here.

Смежные вопросы