Сопоставление по шаблону с Any => Список [Any] => Список [Long]

Используя Scala, я пытаюсь сопоставить шаблон с классом, который возвращает тип значенияAny вытащить любойList[Any] и сопоставление с образцомList[Long] а такжеList[Double] .

Есть ли более элегантный способ сделать это?

Запуск scala 2.11

case class Accumulator (
    name: Option[String],
    value: Option[Any]
)

def bar[T <: Any](value: T): Unit = {
    val listOfAny = value.asInstanceOf[List[Any]]
    val listOfTypes = listOfAny.map(x => x.getClass.getSimpleName).toSet

    listOfTypes.size match {
        case 1 => listOfTypes.head match {
            case "Long" => println("Long list")
            case "Double" => println("Double list")
            case _ => Unit
        }
        case _ => Unit //Probably throw an error log
    }
}

def foo(accumulator: Accumulator): Unit = {
    accumulator match {
        case Accumulator(_, Some(value)) => value match {
            case v if v.isInstanceOf[List[_]] => bar(v)
            case _ => Unit
        }
        case _ => Unit
    }
}


//Should print out "Long List"
foo(Accumulator(None, Some(List(1L, 2L, 3L))))
//Should print out "Double List"
foo(Accumulator(None, Some(List(1.0, 2.0, 3.0))))

Редактировать:

Смог очистить сопоставление строк со стабильными идентификаторами

case class Accumulator (
    name: Option[String],
    value: Option[Any]
)

def bar[T <: Any](value: T): Unit = {
    val listOfAny = value.asInstanceOf[List[Any]]
    val listOfTypes = listOfAny.map(x => x.getClass).toSet

    listOfTypes.size match {
        case 1 => 
            val headType: Class[_] = listOfTypes.head

            // Stable identifiers
            val ClassOfLong: Class[java.lang.Long] = classOf[java.lang.Long]
            val ClassOfDouble: Class[java.lang.Double] = classOf[java.lang.Double]

            headType match {
                case ClassOfLong => 
                    val result: Long = listOfAny.asInstanceOf[List[Long]].sum
                    println(s"Long List sum: $result")
                case ClassOfDouble =>
                    val result: Double = listOfAny.asInstanceOf[List[Double]].sum
                    println(s"Double List sum: $result")
                case _ => Unit
        }
        case _ => Unit //Probably throw an error log
    }
}

def foo(accumulator: Accumulator): Unit = {
    accumulator match {
        case Accumulator(_, Some(value)) => value match {
            case v if v.isInstanceOf[List[_]] => bar(v)
            case _ => Unit
        }
        case _ => Unit
    }
}


//Should print out "Long List sum: 6"
foo(Accumulator(None, Some(List(1L, 2L, 3L))))
//Should print out "Double List sum: 6.0"
foo(Accumulator(None, Some(List(1.0, 2.0, 3.0))))
#
Источник
  • 2
    Более элегантный способ - не использовать Any . Кроме того, ваш фрагмент не компилируется
  • 0
    @ Дима извини, я исправил, что в скрипте не хватает двух валов и обертки накопителя. Не использовать Any - это не вариант, потому что это то, что возвращается из не моего класса. Я действительно жду AccumulableInfo от Spark.
  • 0
    Он по-прежнему не компилируется. Unit - это имя типа, а не значение. Кроме того, я не совсем понимаю, что вы имеете в виду под словом «элегантный». В Any нет ничего «элегантного». Вы должны привести его к реальному типу, чтобы иметь возможность делать с ним что-нибудь полезное.
  • 0
    @ Дима, я не знаю, что сказать. Я буквально скопировал и вставил вышеупомянутое в свой терминал scala, и он компилируется / работает нормально. Это не аргумент в пользу Any , это просто ограничение, с которым я столкнулся. Я бы предпочел не использовать Any . Вся суть этого упражнения в том, чтобы превратить его в реальный тип как конечную цель.
Codelisting
за 0 против
Лучший ответ
case class Accumulator (
    name: Option[String],
    value: Option[Any]
)

def bar[T <: Any](value: T): Unit = {
    val listOfAny = value.asInstanceOf[List[Any]]
    val listOfTypes = listOfAny.map(x => x.getClass).toSet

    listOfTypes.size match {
        case 1 => 
            val headType: Class[_] = listOfTypes.head

            // Stable identifiers
            val ClassOfLong: Class[java.lang.Long] = classOf[java.lang.Long]
            val ClassOfDouble: Class[java.lang.Double] = classOf[java.lang.Double]

            headType match {
                case ClassOfLong => 
                    val result: Long = listOfAny.asInstanceOf[List[Long]].sum
                    println(s"Long List sum: $result")
                case ClassOfDouble =>
                    val result: Double = listOfAny.asInstanceOf[List[Double]].sum
                    println(s"Double List sum: $result")
                case _ => Unit
        }
        case _ => Unit //Probably throw an error log
    }
}

def foo(accumulator: Accumulator): Unit = {
    accumulator match {
        case Accumulator(_, Some(value)) => value match {
            case v if v.isInstanceOf[List[_]] => bar(v)
            case _ => Unit
        }
        case _ => Unit
    }
}


//Should print out "Long List sum: 6"
foo(Accumulator(None, Some(List(1L, 2L, 3L))))
//Should print out "Double List sum: 6.0"
foo(Accumulator(None, Some(List(1.0, 2.0, 3.0))))
за 0 против

Если списки не пустые и все элементы одного типа, вы можете сопоставить как возвращаемый объект, так и первый элемент в списке. Что-то вроде этого

def surprise(): Any = Random.nextInt(3) match {
  case 0 => List(1L, 2L, 3L)
  case 1 => List(0.5, 1.5, 2.5)
  case _ => "foo"
}

0 to 10 foreach { _ =>
  surprise() match {
    case l @ List(_: Long, _*) =>
      println(s"Longs: $l")
    case l @ List(_: Double, _*) =>
      println(s"Doubles: $l")
    case x =>
      println(s"Something else: $x")
  }
}

Выход:

"""
Something else: foo
Something else: foo
Longs: List(1, 2, 3)
Doubles: List(0.5, 1.5, 2.5)
Doubles: List(0.5, 1.5, 2.5)
Doubles: List(0.5, 1.5, 2.5)
Doubles: List(0.5, 1.5, 2.5)
Doubles: List(0.5, 1.5, 2.5)
Something else: foo
Longs: List(1, 2, 3)
Something else: foo
"""
  • 0
    Это похоже на ответ Димы, ответ которого был удален. Одна проблема, с которой я столкнулся, заключается в том, что, поскольку он поступает как Any тип, у меня нет гарантии, что у меня будет список всего одного типа, или я могу получить пустой список. Я предпочитаю не делать предположений и разбираться с этими крайними случаями.
Codelisting
Популярные категории
На заметку программисту