1

在scala中,我有以下代码:

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

该函数isDifferentGroup正在访问外部字符串变量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,我不希望这样。

如何解决?

4

2 回答 2

2

每次调用函数时都会评估函数体中处理的所有内容,因此您无法判断其中的一部分将被静态评估和共享(无需使用某种外部缓存)。因此,您必须将函数体与要提前评估并在函数内部使用的值分开。

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

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);
  }

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

于 2013-07-01T09:59:46.810 回答
0

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

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

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

  def isDifferentGroup(artifact2: DefaultArtifact) = 
    artifact1.getGroupId != artifact2.getGroupId
}
于 2013-07-01T10:00:16.330 回答