繁体   English   中英

代表带有名字参数的函数的FunctionN特性是什么?

[英]What is the FunctionN trait that represents a function taking a by-name parameter?

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 _
                          ^

那是什么

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

Scala别名参数是一种语法糖,可以在需要惰性评估时使代码更具可读性。 如果没有它,我们将需要在所有需要懒惰的东西前面放置“()=>”。 就是说,尽管它在运行时只是一个function0,但是如果您可以将除参数以外的任何内容定义为具有按名称的类型,则在键入系统级别将是有问题的。 还请记住,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 } }

雷克斯·克尔(Rex Kerr)对这个问题的回答为您提供了一个提示:该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
    ...

编辑

为了扩展我的第一条评论,这还表明您不能为by-name参数指定类型

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)
                  ^

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM