Pregunta

Supongamos que tengo algo como esto:

trait Cursor {
}

trait Column[T] {
   def read(cusor: Cursor): T
}

trait ColumnReader {
   def readColumns(columns: Product[Column[_]], cursor: Cursor): Iterable[Any] = {
       for (column <- columns) yield column.read(cursor)
   }
}

El problema de la readColumns() API es que pierdo la información del tipo, es decir, si tengo esto:

object columnString extends Column[String] {
   def read(cursor: Cursor): String = ...
}

object columnInt extends Column[Int] {
   def read(cursor: Cursor): Int = ...
}

Una expresión como new ColumnReader().readColumns((columnString, columnInt)) devoluciones Iterable[Any].Me gustaría devolver algo escrito como Tuple2[String, Int], pero no sé cómo.Pierdo información de tipo útil para el compilador.

Tal vez una biblioteca como Informe Podría ser útil.

Estoy seguro de que Scala tiene alguna herramienta para solucionar problemas como este.

¿Algunas ideas?

¿Fue útil?

Solución

Un ejemplo usando un sin forma. HList

class Cursor

trait Column[T] {
  def read(cusor: Cursor): T
}

class CursorContainer(cursor: Cursor) {
  object mapper extends Poly1 {
    implicit def any[T] = at[Column[T]](_.read(cursor))
  }
}

class ColumnReader {

  def readColumns[T <: HList](columns: T, cursor: CursorContainer)(
    implicit m:Mapper[cursor.mapper.type, T]) = columns.map(cursor.mapper)
}

val columnString = new Column[String] {
  def read(cursor: Cursor): String = ???
}

val columnInt = new Column[Int] {
  def read(cursor: Cursor): Int = ???
}

val reader = new ColumnReader
val cursor =  new CursorContainer(new Cursor)
val result: String :: Int :: HNil =
  reader.readColumns(columnString :: columnInt :: HNil, cursor)

Otros consejos

¿Por qué no usar un contenedor que pueda tomar parámetros de tipo, por ejemplo?Seq o lista?

trait Cursor {
}

trait Column[T] {
   def read(cusor: Cursor): T
}

trait ColumnReader[T] {
   def readColumns(columns: Seq[Column[T]], cursor: Cursor): Iterable[T] = {
       for (column <- columns) yield column.read(cursor)
   }
}

Necesitas un hlist de Folless

También puede usar una aplicación si su número de columnas es limitada.

trait Column[T] {
  def read(c: Cursor) : Id[T]
}
object columnString extends Column[String]
{
  override def read(c: Cursor): Id[String] = "hello"
}

object columnInt extends Column[Int] {
  override def read(c: Cursor): Id[Int] = 3
}

type ColumnReader[T] = Reader[Cursor, T]

val readSpreadSheet1 : ColumnReader[(Int, String)] = Reader {
  c =>
    (columnInt.read(c) |@| columnString.read(c)) { (_,_)}
}

readSpreadSheet1(c)

daría lugar a:

res1: scalaz.Id.Id[(Int, String)] = (3,hello)

También he lanzado una definición de lectores pequeños, para que no tenga que preocuparse por pasar por la instancia de cursor cuando lea una fila.En el inconveniente, debe conocer los tipos de sus columnas de antemano, pero creo que esto también sería cierto cuando use un HLIST.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top