Ответ 1
Как упоминает 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]
по-прежнему является Logger
, поэтому вы можете вызвать любой метод этого класса на нем или передать его функциям, которые принимают в качестве параметра a Logger
.
Этот тип конструкции называется беспошлинным тегом и очень полезен, см. другие приложения и обсуждение здесь и здесь.