如何在scala的foreach中执行操作?

时间:2017-01-02 16:05:24

标签: scala foreach

我正在尝试了解如何在使用foreach时执行操作。对于例如如何使用alist

打印foreach的元素+ 1
scala>alist = List(1,3,5,7)
scala>alist.foreach(println(_+1)) #=> error: missing parameter type...
scala>alist.foreach(println(_).toInt + 1) #=> error: toInt is not a member of Unit

我知道有替代方案(下面),但我正在尝试使用foreach来完成。

scala>for(x<-alist) println(x+1)  #=> 2,4,6,8
scala>alist.map(x => println(x + 1)) #=> 2,4,6,8 

4 个答案:

答案 0 :(得分:5)

  

例如如何使用foreach

为列表的每个元素添加+1

编辑:

要回答您更新的问题,您绝对可以使用foreach

alist.foreach(x => println(x + 1))

您无法在println内使用占位符语法,因为编译器将其推断为:

alist.foreach(x => println(x => x + 1))

根据它的扩张法。 println采用Any类型的参数,因此无法使用加号方法将其绑定到具体类型。

如果您对占位符语法规则感兴趣,请参阅Hidden features of Scala

您不能在Scala中使用List[+A]变异foreach,因为列表是不可变的,foreach返回类型是Unit。您可以做的是使用map转换从现有列表中投射新列表:

scala> val list = List(1,2,3,4)
list: List[Int] = List(1, 2, 3, 4)

scala> val plusOneList = list.map(_ + 1)
plusOneList: List[Int] = List(2, 3, 4, 5)

如果你查看foreach的签名,你会发现它需要一个函数:A => Unit,它接受​​一个A类元素并投射一个Unit。此签名是副作用方法的标志,因为列表是不可变的,这对我们没有帮助。

如果您使用了可变列表,例如ListBuffer,那么您可以对人口使用副作用:

scala> val listBuffer = mutable.ListBuffer[Int]()
listBuffer: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala> (0 to 4).foreach(x => listBuffer += x)

scala> listBuffer
res10: scala.collection.mutable.ListBuffer[Int] = ListBuffer(0, 1, 2, 3, 4)

答案 1 :(得分:2)

我的Scala非常生疏,我没有介质来测试代码,所以请通知我任何语法问题。

在某些情况下,Scala会自动推断出匿名函数的参数类型。根据我的经验,最好只明确说明类型,否则冒险收到编译器的愤怒。如果您要做的就是为每个元素添加一个并打印结果,请尝试:

alist.foreach(
    n: Int => println(n + 1)
)

请注意foreach的目的。当您想要在列表上执行副作用时,可以使用它。如果您的目的是创建第二个列表,其中每个元素是原始列表的+ 1,请使用生成器/映射函数。

关于你的第二个例子,如果你仔细思考,就会明白为什么它不起作用。 println返回void / Unit,然后您尝试访问。{/ p>的toInt方法

编辑:

如评论中所述,在这种情况下,不需要输入注释。我仍然喜欢放置它们。我更喜欢显式类型,除非他们膨胀代码(个人选择)。

答案 2 :(得分:1)

这里的问题是Scala认为你试图将一个函数“(某事)+1”传递给println方法,而不是将它传递给foreach方法。

只执行“println(_)”是有效的,因为在这种情况下,您没有将函数传递给println。相反,您正在定义println的部分应用程序。部分应用程序是一个函数,可以传递给foreach。

这对你有用:

alist.map(_+1).foreach(println)

答案 3 :(得分:1)

在Scala中使用Placeholder Syntax for Anonymous Functions有点棘手。语言规范说:

  

语法类别Expr 的表达式 e 绑定下划线部分 u ,如果满足以下两个条件:(1) e 正确包含 u (2)没有其他语法类别Expr的表达式,它正确包含在 e 中,并且其本身正确包含û

粗体文本确定了Scala编译器如何确定哪个表达式是使用占位符运算符创建的匿名函数 - 它始终是最内层表达式,它正确包含_运算符。在alist.foreach(println(_+1))的情况下,绑定下划线的表达式为_ + 1。它不受整个println(_ + 1)表达式的约束,因为_ + 1正确包含println(_ + 1)。正如在其他答案中已经写过的那样,在这种情况下,您必须使用匿名函数的显式语法:

alist.foreach(x => println(x + 1))

为了完整起见,alist.foreach(println(_+1))会转换为alist.foreach(println(x => x + 1))。由于println接受各种参数,因此编译器无法唯一地推断x的类型,因此在这种情况下缺少参数类型错误。即使你要给x一个类型,也会发生另一个错误,因为foreach期望一个函数接受一个元素类型为alist的参数。