为什么其中一个语句在Scala中编译而在另一个语句中不编译?

时间:2010-04-01 20:44:33

标签: syntax scala

注意:我在这里使用的是Scala 2.7.7,而不是2.8)。

我正在做一些非常简单的事情 - 根据简单的2列CSV文件中的值创建地图 - 我已经足够轻松地完成了它,但我很困惑为什么我的第一次尝试没有编译。这是代码:

// Returns Iterator[String]
private def getLines = Source.fromFile(csvFilePath).getLines

// This doesn't compile:
def mapping: Map[String,String] = {
    Map(getLines map { line: String =>
          val pairArr = line.split(",")
          pairArr(0) -> pairArr(1).trim()
        }.toList:_*)
  }

// This DOES compile
def mapping: Map[String,String] = {
    def strPair(line: String): (String,String) = {
      val pairArr = line.split(",")
      pairArr(0) -> pairArr(1).trim()
    }
    Map(getLines.map( strPair(_) ).toList:_*)
  }

编译器错误是

  

CsvReader.scala:16:   错误:值toList不是其成员   (St ring)=> (java.lang.String中,   java.lang.String)[scalac]可能   原因:可能缺少分号   在`值toList'之前? [scalac]
  } .toList:_ *)[scalac] ^
  [scalac]发现一个错误

那是什么给出的?除了明确的函数定义(与非工作示例中的匿名)和()vs. {}之外,它们看起来应该等同于我。如果我在非工作示例中用括号替换花括号,则错误为“';'预计会发现'val'。“但是如果我删除局部变量定义并将字符串拆分两次并使用parens而不是花括号,它就会编译。有人可以向我解释这个区别,最好有一个链接到Scala文档解释用于包围方法参数时的parens和花括号之间的区别吗?

2 个答案:

答案 0 :(得分:4)

看起来差异是因为您在第一个示例中使用了运算符表示法。如果你添加一组额外的括号,它可以工作:

def mapping: Map[String,String] = {
    Map((getLines map { line: String =>
      val pairArr = line.split(",")
      pairArr(0) -> pairArr(1).trim()
    }).toList:_*)
}

或如果您不使用运算符语法,则可以使用

def mapping: Map[String,String] = {
    Map(getLines.map({ line: String =>
      val pairArr = line.split(",")
      pairArr(0) -> pairArr(1).trim()
    }).toList:_*)
}

我认为问题在于使用普通方法调用语法的优先级高于方法调用的运算符语法。这意味着.toList被应用于匿名函数而不是map方法调用的结果。

答案 1 :(得分:2)

如果您不使用运算符语法,则编译正常:

//Compiles
def mapping: Map[String,String] = {
    Map(getLines.map { line: String =>
          val pairArr = line.split(",")
          pairArr(0) -> pairArr(1).trim()
        }.toList:_*)
  }

如何使用匿名函数没有问题,但正如Ben所提到的,没有map的调用.的语法不等同于典型的Java风格的方法调用。 / p>