在Scala中为元组键入类组合?

时间:2016-02-09 22:47:14

标签: scala typeclass

我试图实现一个稍微更加Scala友好版本的java.util.Scanner,例如而不是做scanner.nextInt(),我希望它解析为其定义解析器的任何类型类,例如而是scanner.read[Int]。以下是我尝试的要点:

import java.io.{BufferedReader, Reader, InputStreamReader, StringReader, InputStream}
import java.util.StringTokenizer

class InputReader(reader: BufferedReader) extends Iterator[String] with AutoCloseable {
  def this(reader: Reader) = this(new BufferedReader(reader))
  def this(inputStream: InputStream) = this(new InputStreamReader(inputStream))
  def this(str: String) = this(new StringReader(str))

  private[this] val tokenizers = Iterator.continually(reader.readLine()).takeWhile(_ != null).map(new StringTokenizer(_)).buffered

  @inline private[this] def tokenizer(): Option[StringTokenizer] = {
    while(tokenizers.nonEmpty && !tokenizers.head.hasMoreTokens) tokenizers.next()
    if (tokenizers.nonEmpty) Some(tokenizers.head) else None
  }

  def read[A: Parser]: A = implicitly[Parser[A]].apply(next())

  def tillEndOfLine(): String = tokenizer().get.nextToken("\n\r")
  override def next() = tokenizer().get.nextToken()
  override def hasNext = tokenizer().nonEmpty
  override def close() = reader.close()
}

trait Parser[A] {
  def apply(s: String): A
}
object Parser {
  def apply[A](f: String => A) = new Parser[A] {
    override def apply(s: String) = f(s)
  }
  implicit val stringParser: Parser[String] = Parser(identity)
  implicit val charParser: Parser[Char] = Parser(s => s.ensuring(_.length == 1, s"Expected Char; found $s").head)
  implicit val booleanParser: Parser[Boolean] = Parser(_.toBoolean)
  implicit val intParser: Parser[Int] = Parser(_.toInt)
  implicit val longParser: Parser[Long] = Parser(_.toLong)
  implicit val bigIntParser: Parser[BigInt] = Parser(BigInt(_))
  implicit val doubleParser: Parser[Double] = Parser(_.toDouble)
  implicit val bigDecimalParser: Parser[BigDecimal] = Parser(BigDecimal(_))
}

这样就可以定义自定义解析器并用作:

val reader = new InputReader(System.in)
reader.read[Int]
reader.read[String]

但是,现在,鉴于我知道如何阅读IntString,我该怎么做reader.read[(Int, String)]

这是我的尝试。

首先,我将Parser类型类更改为InputReader本身:

trait Parser[A] {
  def apply(context: InputReader): A
}
object Parser {
  def apply[A](f: String => A) = new Parser[A] {
    override def apply(context: InputReader) = f(context.next())
  }
}

然后,我为Parser定义Tuple2

implicit def tupleParser[A: Parser, B: Parser]: Parser[(A, B)] = new Parser[(A, B)] {
  override def apply(context: InputReader) = implicitly[Parser[A]].apply(context) -> implicitly[Parser[B]].apply(context)
}

这让我打电话给reader.read[(Int, String)]。但是这非常冗长,因为我现在必须为所有n元组定义解析器。有没有更好的方法呢?

0 个答案:

没有答案