В частичной функции сопоставления с образцом, как заставить isDefined возвращать false для неверных входных данных, которые не могут быть включены в шаблон case? - PullRequest
1 голос
/ 14 марта 2020

В частичной функции, реализованной с сопоставлением с образцом, как заставить isDefined вернуть false для недопустимых входных данных, которые не могут быть включены в шаблон дела?

Например, у меня есть следующее decodeList частичная функция:

case class Arr(items: List[Json]) extends Json
def decode(data: Json): Option[A]
def decodeList: PartialFunction[Json, List[A]] = {
  case Json.Arr(items) =>
    val options = items map decode
    if (options forall (_.isDefined)) options map (_.get)
    else throw new Error // the partial function should be undefined here
}

Я хочу изменить код таким образом, чтобы decodeList.isDefinedAt оценивался как ложный для недопустимых входов. Например, для a, которое decode(a) оценивается как None, decodeList.isDefinedAt(Json.Arr(List(a))) должно оцениваться до false.

Или с другой точки зрения, если я попытаюсь включить условие в шаблон случая как в следующем коде, куда я должен поместить определение val options = items map decode, чтобы его можно было повторно использовать как для шаблона case, так и для блока?

def decodeList: PartialFunction[Json, List[A]] = {
  case Json.Arr(items) if (options forall (_.isDefined)) => 
   options map (_.get)
}

Ответы [ 2 ]

4 голосов
/ 14 марта 2020

Вы можете сделать это, определив пользовательский объект экстрактора, например,

object Options {
  def unapply(items: List[Json]) = Some(items map decode)
}

def decodeList: PartialFunction[Json, List[A]] = {
  case Json.Arr(Options(options)) if (options forall (_.isDefined)) => 
   options map (_.get)
}

, который не особенно удобен, но я не знаю лучшего способа.

Конечно, я бы предложил определить def decodeList(list: Json): Option[List[A]], который лучше подходит для decode и не нуждается в таких обходных путях; тогда Function.unlift(decodeList) если вам нужно PartialFunction.

def decodeList(list: Json) = list match {
  case Json.Arr(items) => 
    val options = items map decode
    if (options forall (_.isDefined)) Some(options map (_.get)) else None
  case _ => None
}
2 голосов
/ 14 марта 2020

Технически, вы можете переопределить isDefinedAt, непосредственно задав PartialFunction, например, так:

def decodeList: PartialFunction[Json, List[A]] = new PartialFunction[Json, List[A]] {
  override def apply(json: Json): List[A] = json match {
    case Json.Arr(items) =>
      val options = items map decode
      options map (_.get)
  }

  override def isDefinedAt(json: Json): Boolean = json match {
    case Json.Arr(items) =>
      val options = items map decode
      options forall (_.isDefined)
  }
}

, однако это отличается от типа isDefinedAt, который компилятор предоставит по по умолчанию .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...