我最近使用scala的parser combinator library编写了一个解析器。我决定对实现感到好奇,然后开始研究。
在reading through the code期间,我看到~
排序使用大小写类来保存左右值。
附有以下评论:
/** A wrapper over sequence of matches.
*
* Given `p1: Parser[A]` and `p2: Parser[B]`, a parser composed with
* `p1 ~ p2` will have type `Parser[~[A, B]]`. The successful result
* of the parser can be extracted from this case class.
*
* It also enables pattern matching, so something like this is possible:
*
* {{{
* def concat(p1: Parser[String], p2: Parser[String]): Parser[String] =
* p1 ~ p2 ^^ { case a ~ b => a + b }
* }}}
*/
case class ~[+a, +b](_1: a, _2: b) {
override def toString = "("+ _1 +"~"+ _2 +")"
}
考虑到上述代码肯定是可能的,并且可以使用a ~ b
将使用{ case a ~ b => ... }
定义的解析器提取为值,那么这种非应用程序是如何工作的呢?我知道scala中的unapply
方法,但是这里没有提供。默认情况下,case类是否提供一个(我认为是)?如果是这样,这个特殊案例类如何变成case a ~ b
而不是case ~(a,b)
?这种模式可以被scala程序员利用吗?
答案 0 :(得分:1)
案例类默认情况下是否提供[
unapply
](我认为是)?
您的怀疑是正确的。 unapply()
是案例类自动提供的众多功能之一。您可以通过以下操作自行验证:
class
定义。scalac -Xshow-phases
以查看所有编译器阶段的描述。)case
。在Bash shell中,它可能看起来像这样。
%%> cat srcfile.scala
class XYZ(arg :Int)
%%> scalac -Xprint:4 srcfile.scala > plainClass.phase4
%%> vi srcfile.scala # add “case”
%%> scalac -Xprint:4 srcfile.scala > caseClass.phase4
%%> diff plainClass.phase4 caseClass.phase4
会遇到很多编译器噪音,但是您会发现,只需将case
添加到类中,编译器就会生成大量额外的代码。
一些注意事项:
case class
实例
Product
和Serializable
混入类型copy()
,productArity
,productElement()
和canEqual()
。productPrefix
,productIterator
,hashCode()
,toString()
和equals()
伴随对象(由编译器创建)
apply()
和unapply()
toString()
如果是这样,这个特殊案例类如何变成
case a ~ b
而不是case ~(a,b)
?
事实证明,这是该语言提供的一种很好的便利(即使不太明显)。
unapply()
调用返回一个Tuple
,可以将其模式化为中缀表示法。同样,这很容易验证。
class XX(val c:Char, val n:Int)
object XX {
def unapply(arg: XX): Option[(Char, Int)] = Some((arg.c,arg.n))
}
val a XX b = new XX('g', 9)
//a: Char = g
//b: Int = 9