Как получить тип класса содержимого Iterable в scala? - PullRequest
0 голосов
/ 17 февраля 2020

Скажем, у меня есть метод, подобный этому:

def getClassFromIterable(iterable: Iterable[Any]): Class[_] = {
  iterable.head.getClass
}

Это получит класс верхней части списка, но не получится, если список пуст.
Как я могу получить класс переданного списка, который имеет ноль или более элементов?

Ответы [ 2 ]

2 голосов
/ 18 февраля 2020

Дополняя ответ Луиса рефлексивным решением, рассмотрим

import scala.reflect.runtime.universe._

def toTable[A <: Product](ps: List[A])(implicit ev: TypeTag[A]) = {
  val separator = "\t\t"
  ps match {
    case Nil =>
      val header = typeOf[A].members.collect { case m: MethodSymbol if m.isCaseAccessor => m.name }.toList
      header.mkString("", separator , "\n")

    case head :: _ =>
      val header = head.productElementNames.toList
      val rows = ps.map(_.productIterator.mkString(separator))
      header.mkString("", separator, "\n") + rows.mkString("\n")
  }
}

, который выводит

case class Point(x: Double, y: Double)
println(toTable(List(Point(1,2), Point(3,4))))

x       y
1.0     2.0
3.0     4.0

На основе Получить список имен полей из дела класс

1 голос
/ 18 февраля 2020

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

import scala.collection.immutable.ArraySeq

trait TableEncoder[T] {
  def header: ArraySeq[String]
  def asRow(t: T): ArraySeq[String]
}

object TableEncoder {
  def toTable[T](data: IterableOnce[T])
                (implicit encoder: TableEncoder[T]): ArraySeq[ArraySeq[String]] = {
    val builder = ArraySeq.newBuilder[ArraySeq[String]]

    builder.addOne(encoder.header)
    builder.addAll(data.iterator.map(encoder.asRow))

    builder.result()
  }
}

, который вы можете использовать так:

final case class Point(x: Int, y: Int)
object Point {
  final implicit val PointTableEncoder: TableEncoder[Point] =
    new TableEncoder[Point] {
      override val header: ArraySeq[String] =
        ArraySeq("x", "y")

      override def asRow(point: Point): ArraySeq[String] =
        ArraySeq(
          point.x.toString,
          point.y.toString
        )
    }
}

TableEncoder.toTable(List(Point(1, 2), Point(3, 3))) 
// res: ArraySeq[ArraySeq[String]] = ArraySeq(
//   ArraySeq("x", "y"),
//   ArraySeq("1", "2"),
//   ArraySeq("3", "3")
// )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...