Подтвердить что ты не робот

Как проверить коротко или неверно в Scala?

В Groovy языке очень просто проверить для null или false как:

groovy код:

def some = getSomething()
if(some) {
// do something with some as it is not null or emtpy 

}

В Groovy, если some есть null или является пустой строкой или является нулевым числом и т.д., будет оцениваться как false. Что такое сжатый метод тестирования для null или false в Scala? Каков простой ответ на эту часть вопроса, предполагая, что some - это просто тип Java String?

Также еще один лучший метод в Groovy:

def str = some?.toString()

что означает, что если some не null, тогда метод toString на some будет вызываться вместо того, чтобы бросать NPE в случае, если some был null. Что похоже в Scala?

4b9b3361

Ответ 1

Что вам может не хватать, так это то, что функция типа getSomething в Scala, вероятно, не вернет нулевую, пустую строку или нулевое число. Функция, которая может возвращать значимое значение или, возможно, не имеет в качестве возвращаемого значения Option - возвращает Some(meaningfulvalue) или None.

Затем вы можете проверить это и обработать значимое значение с помощью

 val some = getSomething()
 some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
 }

Поэтому вместо того, чтобы пытаться закодировать значение "сбой" в возвращаемом значении, Scala имеет определенную поддержку общего случая "вернуть что-то значимое или указать отказ".

Сказав, что Scala совместим с Java, а Java возвращает значения из функций все время. Если getSomething - это функция Java, которая возвращает null, существует объект factory, из которого будут выведены некоторые или None из возвращаемого значения.

So

  val some = Option(getSomething())
  some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
  }

... который довольно прост, я утверждаю, и не пойду на NPE на вас.

Другие ответы делают интересные и идиоматические вещи, но это может быть больше, чем вам нужно прямо сейчас.

Ответ 2

Ну, Boolean не может быть null, если не передано как параметр типа. Способ обработки null состоит в том, чтобы преобразовать его в Option, а затем использовать все элементы Option. Например:

Option(some) foreach { s => println(s) }
Option(some) getOrElse defaultValue

Так как Scala является статическим типом, вещь не может быть "нулевой или пустой строкой или является нулевым числом и т.д.". Вы можете передать Any, который может быть любой из этих вещей, но тогда вам придется сопоставлять каждый тип, чтобы иметь возможность делать что-нибудь полезное с ним в любом случае. Если вы окажетесь в этой ситуации, вы, скорее всего, не будете выполнять идиоматические Scala.

Ответ 3

В Scala описанные вами выражения означают, что метод, называемый ?, вызывается на объекте с именем some. Регулярно объекты не имеют метода под названием ?. Вы можете создать свое собственное неявное преобразование в объект с помощью метода ?, который проверяет наличие null ness.

implicit def conversion(x: AnyRef) = new {
  def ? = x ne null
}

Вышеупомянутое, по сути, преобразует любой объект, на который вы вызываете метод ?, в выражение в правой части метода conversion (у которого есть есть ?). Например, если вы это сделаете:

"".?

компилятор обнаружит, что объект String не имеет метода ? и переписывает его на:

conversion("").?

Иллюстрируется в интерпретаторе (обратите внимание, что при вызове методов на объектах вы можете опустить .):

scala> implicit def any2hm(x: AnyRef) = new {
     |   def ? = x ne null
     | }
any2hm: (x: AnyRef)java.lang.Object{def ?: Boolean}

scala> val x: String = "!!"
x: String = "!!"

scala> x ?
res0: Boolean = true

scala> val y: String = null
y: String = null

scala> y ?
res1: Boolean = false

Итак, вы можете написать:

if (some ?) {
  // ...
}

Или вы можете создать неявное преобразование в объект с помощью метода ?, который вызывает указанный метод для объекта, если аргумент не является null - выполните следующее:

scala> implicit def any2hm[T <: AnyRef](x: T) = new {
     |   def ?(f: T => Unit) = if (x ne null) f(x)
     | }
any2hm: [T <: AnyRef](x: T)java.lang.Object{def ?(f: (T) => Unit): Unit}

scala> x ? { println }
!!

scala> y ? { println }

чтобы вы могли написать:

some ? { _.toString }

Создавая (рекурсивно) ответ на soc, вы можете сопоставить соответствие по x в приведенных выше примерах, чтобы уточнить, что ? делает в зависимости от типа x.: D

Ответ 4

Вы можете написать некоторую оболочку самостоятельно или использовать тип параметра.

Я действительно не проверял бы на null. Если есть null где-то, вы должны исправить его и не строить проверки вокруг него.

На вершине ответа axel22:

implicit def any2hm(x: Any) = new {
  def ? = x match {
    case null => false
    case false => false
    case 0 => false
    case s: String if s.isEmpty => false
    case _ => true
  }
}

Изменить: похоже, это либо сбой компилятора, либо не работает. Я буду исследовать.

Ответ 5

Если вы используете extempore null-safe coalescing operator, вы можете написать пример str как

val str = ?:(some)(_.toString)()

Он также позволяет вам цепочки, не беспокоясь о null (таким образом, "коалесцируя" ):

val c = ?:(some)(_.toString)(_.length)()

Конечно, этот ответ касается только второй части вашего вопроса.

Ответ 6

То, что вы просите, есть в строке Safe Navigation Operator (?.) Groovy, andand gem от Ruby или вариант доступа экзистенциального оператора (?.) от CoffeeScript, Для таких случаев я обычно использую метод ? моего RichOption[T], который определяется следующим образом

class RichOption[T](option: Option[T]) {
  def ?[V](f: T => Option[V]): Option[V] = option match {
    case Some(v) => f(v)
    case _ => None
  }
}

implicit def option2RichOption[T](option: Option[T]): RichOption[T] =
  new RichOption[T](option)

и используется следующим образом

scala> val xs = None
xs: None.type = None

scala> xs.?(_ => Option("gotcha"))
res1: Option[java.lang.String] = None

scala> val ys = Some(1)
ys: Some[Int] = Some(1)

scala> ys.?(x => Some(x * 2))
res2: Option[Int] = Some(2)

Ответ 7

Использование сочетания шаблонов, предложенное в нескольких ответах, является хорошим подходом:

val some = Option(getSomething())
  some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
  }

Но, немного подробный.

Я предпочитаю map an Option следующим образом:

Option(getSomething()) map (something -> doSomethingWith(something))

Один лайнер, короткий, понятный.

Причиной этому является вариант, который можно рассматривать как некоторая коллекция - специальная снежинка коллекции, содержащая либо нулевые элементы, либо точно один элемент типа, и поскольку вы можете сопоставить List [A] с List [B], вы можете сопоставить опцию [A] с опцией [B]. Это означает, что если ваш экземпляр Option [A] определен, то есть он является некоторым [A], результатом является Some [B], иначе это None. Это действительно мощно!