程序员人生 网站导航

scala中判断一个对象是否是元组(Tuple)

栏目:综合技术时间:2013-12-19 10:13:09

在scala user邮件列表中看到一个函数,判断一个对象是否是元组。从这个函数中,Easwy才了解到原来模式匹配(Pattern Match)也可以应用于正则表达式,这使得在scala中使用正则表达式(regex)更加容易了。另外,这个函数还展现了scala的另外两个特点:

  1. 尽量使用递归解决方案,而不是使用循环。这样做的优点之一是避免使用变量,优点之二是代码简洁。是否有其它优点,Easwy仍在总结。但Easwy始终有个担心,递归会不会导致效率降低?会不会有堆栈溢出风险?
  2. 使用Option类型做为函数返回值。使用Option类型的好处很明显,这样你的函数既可以返回执行失败的情况(None),也可以在执行成功时给出有用的返回值。这比使用tru/false作为返回值方便很多。

函数主体如下,为了方便讲解,在前面加了行号:

 val Ptrn = """scala.Tuple(d+)""".r def checka( x: Class[ _ ]) : Option[ Int ] = x.getName match {      case Ptrn( i ) => Some( i.toInt )      case _ => { val sc = x.getSuperclass; if( sc != null ) checka( sc ) else None } } def isTuple( x: AnyRef ) = if( x.isInstanceOf[ Product ]) checka( x.getClass ) else None    
  1. 行1定义了一个Pattern对象,可以看到,在scala中使用正则表达式非常的简单。
  2. 行3定义了一个递归函数checka(),它的参数是Class[_],返回值是Option[Int]类型。参数”Class[_]“的意思是这个函数可以接受任意Class[A]类型,也就是接受任何参数化的Class类型(Type Parameterization)。

  3. 从行3的后半句,到行5,是一个模式匹配,检查类的名字是否匹配正则表达式Ptrn。如果类名匹配Ptrn,也就是说是一个Tuple,则返回它的维数。例如,对Tuple3返回Some(3)。如果类名不匹配Ptrn,递归调用checka()检查其父类是否为Tuple,如果全部失败,则返回None。
  4. 行8定义isTuple()函数,调用checka()判断是否为Tuple。它首先会检查x是否是一个Product实例,满足时才调用checka(),否则直接返回None。

Easwy感觉checka()函数中的递归写的不是很好,在看过”The Little Schemer”后,Easwy更倾向与下面的写法:

  def checka(x: Class[_]): Option[Int] = x match {    case null => None    case _ => x.getName match {      case Ptrn(i) => Some(i.toInt)      case _ => checka(x.getSuperclass)    }  }     

下面是Easwy用来测试该函数的程序,全文如下:

object TestTuple {  def main(args: Array[String]) {    class ttt(a: Any, b: Any, c: Any) extends Tuple3(a, b, c)    val test = List(new Tuple2(1, 2), new ttt(1, 2, 3), "Hello World")    for (elem <- test)      isTuple(elem) match {        case None => println("Not Tuple")        case Some(x) => println("Is Tuple" + x)      }  }  val Ptrn = """scala.Tuple(d+)""".r  def checka(x: Class[_]): Option[Int] = x match {    case null => None    case _ => x.getName match {      case Ptrn(i) => Some(i.toInt)      case _ => checka(x.getSuperclass)    }  }  def isTuple( x: AnyRef ) = if( x.isInstanceOf[ Product ]) checka( x.getClass ) else None}

有兴趣的朋友可以编译运行一下,体会一下scala的简捷与优雅。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐