我正在尝试了解如何在使用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
答案 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
的参数。