在Scala中获取数组元素仅适用于显式应用方法

时间:2016-11-11 18:12:06

标签: arrays scala

通过apply方法访问Scala中的集合元素。话虽如此,我试图从标准输入读取数字,并在第一行中将第二个作为int。

  def main(args: Array[String]): Unit = {
    val number = StdIn.readLine().split(" ").map(_.toInt)(1)
  }

IntelliJ标记此1并显示错误(编译尝试后显示错误):

  

错误:(11,60)类型不匹配;发现:Int(1)要求:   scala.collection.generic.CanBuildFrom [数组[字符串],诠释,?]       val number = StdIn.readLine()。split(“”)。map(_。toInt)(1)

折叠括号中的表达式也没有帮助。但是,当我将映射输入拆分为int数组并将元素转换为其他行时,一切正常。

  def main(args: Array[String]): Unit = {
    val numbers = StdIn.readLine().split(" ").map(_.toInt)
    numbers(1)
  }

显式调用apply也可以完成工作:

val number = StdIn.readLine().split(" ").map(_.toInt).apply(1)

为什么会发生这种奇怪的行为?通过array(5)获取元素只是array.apply(5)的快捷方式,不是吗?

2 个答案:

答案 0 :(得分:2)

正如编译器已经指出的那样,map定义了两个arg列表。第二个包含一个隐式参数:implicit bf: CanBuildFrom[Repr, B, That]

对于绝大多数情况,用户不必担心指定第二个arg。具体来说,在您的情况下,这就是编译器"指出":

StdIn.readLine().split(" ").map(_.toInt)(Array.canBuildFrom[Int])

因此,如果不需要写出apply,则以下是唯一的选择:

StdIn.readLine().split(" ").map(_.toInt)(Array.canBuildFrom[Int])(1)

有点反直觉的是,添加一组括号仍然不能解决问题:

( StdIn.readLine().split(" ").map(_.toInt) )(1)  //does not compile, same error

也许最好通过一个更简单的例子来展示自己的目标。考虑以下功能:

def add(x:Int)(y:Int) = x + y

add(2)的类型为Int => Int(因为我们尚未指定y)。请注意,在其周围添加一组括号并不会更改返回类型,即(add(2))仍然具有类型Int => Int。同样,在(Array("1").map(_.toInt))(1)使用速记之前,CanBuildFrom仍然需要apply的实例。

有关Scala集合的建议阅读:

和隐式范围:

答案 1 :(得分:1)

您与map的隐含参数发生冲突。这是需要明确调用apply的情况之一。

这是一些复制错误的REPL:

scala> class Foo {
  def apply() { println("bar") }
}

scala> def makeFoo(): Foo = new Foo

scala> makeFoo()()
bar // got the println from the apply here

scala> def makeFooImplicit()(implicit x: Int): Foo = new Foo

scala> implicit val x = 5

scala> makeFooImplicit()()
  <console>:11: error: not enough arguments for method makeFooImplicit:(implicit x: Int)Foo.
  Unspecified value parameter x.
          makeFooImplicit()()