我试图实现一个稍微更加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]
但是,现在,鉴于我知道如何阅读Int
和String
,我该怎么做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元组定义解析器。有没有更好的方法呢?