什么是表示采用名称参数的函数的函数特征?

时间:2011-11-24 00:27:51

标签: scala

Scala中的函数是一个实现FunctionN特征之一的对象。例如:

scala> def f(x: Int) = x * x
f: (x: Int)Int

scala> val ff = f _
ff: Int => Int = <function1>

scala> val fff: Function1[Int, Int] = f _
fff: Int => Int = <function1>

到目前为止,这么好。但是如果我们有一个带有名字参数的函数呢?它当然仍然实现了FunctionN特征之一:

scala> def g(x: => Int) = x * x
g: (x: => Int)Int

scala> val gg = g _
gg: => Int => Int = <function1>

scala> gg.isInstanceOf[Function1[_, _]]
res0: Boolean = true

但究竟是什么类型的呢?这不是Function1[Int, Int]

scala> val ggg: Function1[Int, Int] = g _
<console>:8: error: type mismatch;
 found   : => Int => Int
 required: Int => Int
       val ggg: Function1[Int, Int] = g _
                                      ^

也不是Function1[Function0[Int], Int]

scala> val ggg: Function1[Function0[Int], Int] = g _
<console>:8: error: type mismatch;
 found   : => Int => Int
 required: () => Int => Int
       val ggg: Function1[Function0[Int], Int] = g _
                                                 ^

Function1[=> Int, Int]无法编译:

scala> val ggg: Function1[=> Int, Int] = g _
<console>:1: error: identifier expected but '=>' found.
       val ggg: Function1[=> Int, Int] = g _
                          ^

那是什么?

2 个答案:

答案 0 :(得分:5)

按名称非常有用但在类型系统之外不安全

Scala by-name参数是一种语法糖,可以在需要延迟评估时使代码更具可读性。没有它我们需要把“()=&gt;”在所有需要懒惰的事物面前。也就是说,虽然它在运行时只是一个函数0,但如果您可以将参数以外的任何内容定义为具有按名称类型,则在键入系统级别会出现问题。还要记住,FunctionN特性主要用于实现和Java互操作性,因为Java和JVM中没有函数类型。

明确

如果您确实需要明确输入,则以下内容将允许您具有限制性

def g(x: => Int) = x * x
val ggg: (=> Int) => Int = g _

更复杂的输入

名字输入只能在函数类型声明的参数部分中使用。然后,函数类型本身可以在其他参数化类型中使用。

var funks: List[(=> Int) => Int] = Nil
funks ::= ggg
funks foreach { _ { println("hi"); 5 } }

答案 1 :(得分:1)

Rex Kerr对this question的回答给出了一个提示:by-name参数最终转换为Function0,但可能在编译时特别处理。

您可以验证这一点:

scala> gg(sys.error("me"))
java.lang.RuntimeException: me
    at scala.sys.package$.error(package.scala:27)
    at $anonfun$1.apply(<console>:10)
    at $anonfun$1.apply(<console>:10)
    at scala.Function0$class.apply$mcI$sp(Function0.scala:34)
    at scala.runtime.AbstractFunction0.apply$mcI$sp
    ...

修改

要扩展我的第一条评论,这也表示您无法为名字参数提供类型

def test[A: Manifest](fun: Function1[A, Int]): Unit =
  println("Found " + implicitly[Manifest[A]])

scala> test(gg)
<console>:11: error: No Manifest available for => Int.
              test(gg)
                  ^