在scala闭包中预先计算一些代码。

时间:2013-07-01 09:41:19

标签: scala closures

在scala中,我有以下代码:

def isDifferentGroup(artifact2: DefaultArtifact) = getArtifact(artifact1Id).getGroupId != artifact2.getGroupId
val artifacts = getArtifacts().filter(isSameGroup)

函数isDifferentGroup正在访问外部String变量artifactId(闭包)。

我想避免为列表中的每个项目计算getArtifact(artifactId)

我可以这样做:

val artifact1: DefaultArtifact = getArtifact(artifact1Id)
def isDifferentGroup(artifact2: DefaultArtifact) = artifact1.getGroupId != artifact2.getGroupId
val artifacts = getArtifacts().filter(isSameGroup)

但是,我们在函数artifact1之外创建变量isDifferentGroup,这很难看,因为此变量仅在函数isDifferentGroup内使用。

如何解决?

一种可能性是使部分功能如下:

def isDifferentGroup(artifact1: DefaultArtifact)(artifact2: DefaultArtifact) = artifact1.getGroupId != artifact2.getGroupId
val artifacts = getArtifacts().filter(isDifferentGroup(getArtifact(artifact1Id)))

但是,我必须将代码getArtifact(artifactId)移到isDifferentGroup函数之外,我不希望这样。

如何解决?

2 个答案:

答案 0 :(得分:2)

每次调用函数时都会对函数体中处理的所有内容进行求值,因此您无法分辨它的一部分是否会被静态评估和共享(无需使用某种外部缓存)。因此,您必须将函数体与要预先评估的值分开,并在函数内部使用。

但是,您可以将这些值括在一个块中,以便形成一个紧凑的块。我能想到的最好的事情是使用函数类型声明val,例如

val isDifferentGroup: DefaultArtifact => Boolean = {
    val gid = getArtifact(artifact1Id).getGroupId
    (artifact2: DefaultArtifact) => {
        (gid != artifact2.getGroupId)
    }
}

这样,您可以在主val块(此处为gid)中明确说明静态评估哪个部分,以及响应artifact2参数评估哪个部分。您可以像调用方法一样调用isDifferentGroup

println(isDifferentGroup(someArtifact))

这基本上只是创建像

这样的封装类的另一种方式
val isDifferentGroup: DefaultArtifact => Boolean =
  new Function1[DefaultArtifact,Boolean] {
    val gid = getArtifact(artifact1Id).getGroupId

    override def apply(artifact2: DefaultArtifact): Boolean =
        (gid != artifact2.getGroupId);
  }

您甚至可以将其声明为lazy val,在这种情况下,gid最多只需 ,这是第一次调用该函数。

答案 1 :(得分:0)

为什么不创建一个类来封装(私有)值和功能?

这段代码可能无法编译,只是为了说明它:

class Artifact(artifact1Id: Id) {
  private val artifact1: DefaultArtifact = getArtifact(artifact1Id)

  def isDifferentGroup(artifact2: DefaultArtifact) = 
    artifact1.getGroupId != artifact2.getGroupId
}