如何编写零参数函数?

ego*_*doe 7 scala function-composition

我想要实现的是将 2 个函数(其中一个是没有 arg 函数)合二为一。

这是一个示例,可以让您了解我在做什么:

object Test extends App {

  val zeroArgFunc = () => 10
  val intArgFunc = (i: Int) => s"hello $i"
  val stringArgFunc = (s: String) => println(s)

  // This line works perfectly fine.
  val intAndThenString: Int => Unit = stringArgFunc compose intArgFunc

  // But this line fails with 'type mismatch' compilation error.
  val zeroAndThenInt: () => String = intArgFunc compose zeroArgFunc

}
Run Code Online (Sandbox Code Playgroud)

编译错误:

[error]  found   : () => Int
[error]  required: ? => Int
[error]   val zeroAndThenInt: () => String = intArgFunc compose zeroArgFunc
[error]                                                         ^
[error] one error found
Run Code Online (Sandbox Code Playgroud)

知道出了什么问题吗?

[UPD] Scala 版本是 2.13.1(如果重要的话)。

Mar*_*lic 5

脱糖() => 10我们有

new Function0[Int] { def apply() = 10 }
Run Code Online (Sandbox Code Playgroud)

并且Function0没有composeandThen方法

trait Function0[... +R] extends ... { ...
  def apply(): R
  override def toString(): String = "<function0>"
}
Run Code Online (Sandbox Code Playgroud)

所以它似乎Function0无法组成。

另一方面(i: Int) => s"hello $i"(s: String) => println(s)对应于Function1哪个确实compose定义了方法,因此它们可以组合。

考虑更改() => 10(_: Unit) => 10which 将类型从 更改Function0Function1,然后

(intArgFunc compose zeroArgFunc)()
Run Code Online (Sandbox Code Playgroud)

输出res4: String = hello 10


解决@Duelist 的评论,恕我直言,Function0[T]在语义上不等同于Function1[Unit, T]. 例如,给定

val f = () => 10
val g = (_: Unit) => 10
Run Code Online (Sandbox Code Playgroud)

然后

f()
g()
Run Code Online (Sandbox Code Playgroud)

确实输出

res7: Int = 10
res8: Int = 10
Run Code Online (Sandbox Code Playgroud)

然而

f(println("woohoo")) // error: no arguments allowed for nullary method apply                                                             
g(println("woohoo")) // OK!
Run Code Online (Sandbox Code Playgroud)

我们看到两者没有相同的行为。尽管如此,如果您想将它们视为等效的,也许您可​​以定义一个扩展方法Function0并明确转换,例如

implicit class Fun0ToFun1[A, B](f: () => A) {
  def toFun1: Unit => A = (_: Unit) => f()
}
Run Code Online (Sandbox Code Playgroud)

将允许以下语法

(intArgFunc compose zeroArgFunc.toFun1)()
Run Code Online (Sandbox Code Playgroud)

通过@egordoe寻址评论,外的开箱compose只为过定义Function1,因此Function2Function3等等,不能组成一样Function0。但是我们可以定义扩展composeN的功能的方法,例如,假设我们要组成Function1Function0,然后

implicit class ComposeFun1WithFun0[A, B](f1: A => B) {
  def compose0(f2: () => A): () => B = () => f1(f2())
}
Run Code Online (Sandbox Code Playgroud)

(intArgFunc compose0 zeroArgFunc)()
Run Code Online (Sandbox Code Playgroud)

  • @Duelist 请参阅[不带参数的函数,以单位作为参数](/sf/answers/194235191/) (2认同)