for/yield 中的赋值表达式是 Scala 的原因吗?

Assignment expression in for/yield cause of Scala?

我的代码如下所示:

  type Occurrences = List[(Char, Int)]
  def subtract(x: Occurrences, y: Occurrences): Occurrences = for {
    (theChar, theInt) <- x
    yMap = y.toMap
    finalInt = theInt - yMap.getOrElse(theChar,0)
    if finalInt != 0
  } yield (theChar, finalInt)

我想知道 yMap= y.toMap 是只计算一次还是多次。如果它被计算多次,让它只计算一次的正确语法是什么?

x的每个元素计算一次; (theChar, theInt) <- x 下方的所有内容 是。

如果您只想对某项求值一次,请将其排除在循环遍历每个元素的任何内容之外。例如,

def subtract(x: Occurrences, y: Occurrences): Occurrences = {
  val yMap = y.toMap
  for {
    (theChar, theInt) <- x
    finalInt = theInt - yMap.getOrElse(theChar,0)
    if finalInt != 0
  } yield (theChar, finalInt)
}

会成功的。

简答

只需将 ymap = y.toMap 部分带出 for 理解即可。

def subtract(x: Occurrences, y: Occurrences): Occurrences = {
    val yMap = y.toMap
    for {
      (theChar, theInt) <- x
      finalInt = theInt - yMap.getOrElse(theChar, 0)
      if finalInt != 0
    } yield (theChar, finalInt)
  }

详细解答

Scala For Comprehensions 只是一个语法糖。

例如你的代码将被编译器翻译成下面的代码(不完全是下面的代码,但概念是一样的):

def subtract(x: Occurrences, y: Occurrences): Occurrences = x map {
    case (theChar, theInt) =>
      def yMap = y.toMap
      def finalInt = theInt - yMap.getOrElse(theChar, 0)
      (theChar, finalInt)
  } filter {
    case (_, theInt) =>
      theInt != 0
  }

因此,map 部分内的任何表达式都将针对集合中的每个项目执行(在本例中为 x)。通过将 y = y.toMap 部分移出 for 块,代码将被翻译成:

  def subtract(x: Occurrences, y: Occurrences): Occurrences = {
    def yMap = y.toMap
    x map {
      case (theChar, theInt) =>
        def finalInt = theInt - yMap.getOrElse(theChar, 0)
        (theChar, finalInt)
    } filter {
      case (_, theInt) =>
        theInt != 0
    }
  }

这很可能是您真正想要的。