我正在学习Scala并正在尝试使用命令行。我无法理解为什么第二行无法编译。有人可以解释一下。
val list = List(1,2,3,4)
list.map(_+1) //This works. List(2,3,4,5)
list.map(List(_+1)) //But, Compilation Fails here
list.map(x=>List(x+1)) //This works. List(List(2),List(3),List(4),List(5))
谢谢。
答案 0 :(得分:6)
Scala会将_
(在占位符位置使用时)扩展为x => x
,除非此类扩展会导致身份函数(在此答案结尾处更多内容):
list.map(_+1) // same as list.map(x => x + 1) (1)
list.map(List(_+1)) // same as list.map(List(x => x+1)) (2)
对于(1)
,scala可以推断x
的类型为Int
(自list: List[Int]
起)。
但(2)
失败,
error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
因为scala无法在x
中推断出List(x => x+1)
的类型。
关于扩展和身份功能:
scala> list.map(List(_))
res3: List[List[Int]] = List(List(1), List(2), List(3), List(4))
有效,因为list.map(List(x => x))
扩展被拒绝了,下一个可能的扩展名是list.map(x => List(x))
,这会产生res3
。
答案 1 :(得分:1)
list
的类型为List[Int]
。因此,list.map(...)
的参数必须是从Int
到某个函数的函数。
你试图用List(_+1)
创建的是一个从整数到整数的函数列表,这些函数碰巧有一个元素:后继函数。
无法编译,因为这是Scala编译器无法推断表达式类型的情况之一。但实际上,List[_]
是从Int
到
val f = List(99, 88, 77)
f(1) // -> 88
因此,要编译代码,必须给编译器一些提示,以便进行类型检查:
val list = List(1, 2, 3, 4)
list.map(List[Function[Int, Int]](_ + 1))
// ^^^^^^^^^^^^^^^^^^^^ type annotation
这也是有效的:
list.map(List[Int => Int]](_ + 1))
它将编译,但它会在运行时失败,因为您正在尝试获取单元素列表的元素1,2,3和4。如果列表仅包含零(该特定列表的唯一有效索引),则它可以工作:
val list = List(0, 0, 0)
list.map(List[Function[Int, Int]](_ + 1))
// -> evaluates to a list of three functions
...或者如果函数列表包含足够的索引1,2,3和4元素:
val list = List(1, 2, 3, 4)
list.map(List[Function[Int, Int]]( // a list of 5 functions:
_ + 1, // 0) the successor function,
_ * 10, // 1) the "append a zero" function,
Math.abs, // 2) the absolute value function,
_ / 2, // 3) the half function
x => 2 // 4) the constant function with value 2
))
// -> evaluates to a list of four functions. Can you guess which ones?