如何存储方法vals而不是每次方法调用都重新创建它们

时间:2014-11-09 21:52:05

标签: scala

我有Scala类,哪些方法使用了很多正则表达式。每个类方法都使用一些正则表达式模式。 从代码模块化的角度来看,我应该将这些模式存储在方法中:

class Bar {
    def foo() {
        val patt1 = "[ab]+".r
        val patt2 = "[cd]+".r
        /*...*/
    }
}

但这种方法效率很低。每次方法调用都会重新编译模式。 我可以将它们直接移到课堂上:

class Bar {
    val fooPatt1 = "[ab]+".r
    val fooPatt2 = "[cd]+".r
    /*...*/
}

但如果我有30种方法,它看起来很难看。

我最终得到了一些使用val和匿名函数的混合解决方案:

val z = {
    val patt1 = "[ab]+".r
    val patt2 = "[cd]+".r
    () => { /* ... */ }
}

但我不确定使用val来存储函数与def相比是否有一些缺点。也许还有其他干净的解决方案来存储方法常量而不会污染类?

3 个答案:

答案 0 :(得分:2)

使用val完全没问题。可能会有(非常)小的性能损失,但在大多数(99.9%)应用程序中不是问题。

您还可以为方法

创建一个类
// The extends is not needed, although you might want to hide the Foo type
class Foo extends (() => ...) {
  val patt1 = "[ab]+".r
  val patt2 = "[cd]+".r

  def apply() = {
    ...
  }
}

然后在课堂上:

class Bar {
  val foo = new Foo
}

另一种解决方案是使用特征

trait Foo {
  private lazy val patt1 = "[ab]+".r
  private lazy val patt2 = "[cd]+".r

  def foo() = ...
}

class Bar extends Foo with ...

请注意,如果您在单个班级中使用不同的方法,则可能表示违反了单一责任原则。将它们移动到自己的类(或特征)也可以解决该问题。

答案 1 :(得分:2)

我会在每个方法中都使用必要的正则表达式自己的特性:

class Bar extends AMethod with BMethod

trait AMethod {
  private val aPattern = """\d+""".r   
  def aMethod(s: String) = aPattern.findFirstIn(s)
}

trait BMethod {
  private val bPattern = """\w+""".r
  def bMethod(s: String) = bPattern.findFirstIn(s)
}
  • 清洁
  • 分离
  • 易于测试(对象AMethodSpec使用AMethod扩展属性(" AMethod")...)

答案 2 :(得分:0)

我考虑了克里斯的评论。将模式放到伴侣对象可能是最有效的方法,但是当我们有更多方法时非常不洁净。 EECOLOR解决方案效率较低但更清洁。特征可防止在每个方法调用上重新创建模式。不幸的是,scala不会在多个类实例中使用相同的编译模式:

(new X).patt1==(new X).patt1 // would be false.

我将这两种方法结合起来,而不是使用了对象。

object X {
  object method1 {
    val patt1 = "a".r
  }
  object method2 {
    val patt1 = "a".r
  }
}
class X {
  def method1 = {
    import X.method1._
    patt1
  }
  def method2 = {
    import X.method2._
    patt1
  }
}

(new X).method1 == (new X).method1 // true
(new X).method2 == (new X).method2 // true

虽然这种方法有效,但我认为scala应该为开箱即用的问题提供一些解决方案。模式是最简单的例子。我们可以有其他不可变对象,初始化要贵得多。 在外面某处提取方法内部仍然不清楚。与懒惰的vals一样,这样做会很好。添加一个修改器应该确保所有实例和方法调用中的值只是实例一次。它会是这样的:

def method1 {
 static val  x = new VeryExpensiveObject
}