Scala 方法类型和作为参数的方法

发布于 2024-12-09 03:10:28 字数 985 浏览 0 评论 0 原文

在下面的代码示例中,我不明白为什么函数 fun 可以作为参数传递给方法 addAction。方法 fun 的类型为 Unit,而方法 addAction 则需要一个类型为 () =>; 的函数。单位

如果 fun 的类型为 () =>; Unit,那么当我尝试将 fun 添加到操作列表时,为什么编译器会抱怨 fun 的类型为 Unit : actions = fun :: actions

package myscala

object MyScala {

  def fun() { println("fun1 executed.") }

  def addAction(a: () => Unit) {
    actions = a :: actions
  }

  var actions: List[() => Unit] = List()

  def main(args: Array[String]) {
    // the following line would produce a compiler error (found: Unit, required: () => Unit), it's OK
    // actions = fun :: actions
    actions = (() => fun) :: actions // OK
    // I would expect the same compiler error here (found: Unit, required: () => Unit), but it's OK why?
    addAction(fun)
    actions.foreach(_()) // prints twice "fun1 executed"
  }
}

In the following code example, I do not understand why the function fun can be passed as an argument to the method addAction. The method fun is of type Unit, while the method addAction expects a function of type () => Unit.

If fun is of type () => Unit, then why does the compiler complain that fun is of type Unit, when I try to add fun to the actions list: actions = fun :: actions?

package myscala

object MyScala {

  def fun() { println("fun1 executed.") }

  def addAction(a: () => Unit) {
    actions = a :: actions
  }

  var actions: List[() => Unit] = List()

  def main(args: Array[String]) {
    // the following line would produce a compiler error (found: Unit, required: () => Unit), it's OK
    // actions = fun :: actions
    actions = (() => fun) :: actions // OK
    // I would expect the same compiler error here (found: Unit, required: () => Unit), but it's OK why?
    addAction(fun)
    actions.foreach(_()) // prints twice "fun1 executed"
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

兰花执着 2024-12-16 03:10:28

以此作为介绍性示例:

def fun() { println("fun1 executed.") }

val a1 = fun
val a2: () => Unit = fun

这两行都可以编译并且(由于类型推断)它们看起来是等效的。然而,a1 的类型为 Unit,而 a2 的类型为 () =>单位...这怎么可能?

由于您没有显式提供 a1 类型,编译器会将 fun 解释为 Unit 类型的方法 fun 调用,因此a1的类型与fun的类型相同。这也意味着该行将打印fun1执行。

但是,a2已经显式声明了() =>;的类型。单位。编译器在这里为您提供帮助,它理解因为上下文需要 () => 类型的函数,所以编译器可以帮助您。 Unit 并且您提供了与该类型匹配的方法,它不应该调用该方法,而应将其视为第一类函数!

您不一定要显式指定 a1 的类型。说:

val a1 = fun _

你现在明白你的问题出在哪里了吗?

Take this as an introductory example:

def fun() { println("fun1 executed.") }

val a1 = fun
val a2: () => Unit = fun

Both lines compile and (thanks to type inference) they look equivalent. However a1 is of type Unit while a2 is of type () => Unit... How is this possible?

Since you are not explicitly providing type of a1, compilers interprets fun as a method fun call of type Unit, hence the type of a1 is the same as type of fun. It also means that this line will print fun1 executed.

However, a2 has explicitly declared type of () => Unit. The compiler helps you here and it understands that since the context requires a function of type () => Unit and you provided a method matching this type, it shouldn't call that method, but treat it as first class function!

You are not doomed to specify type of a1 explicitly. Saying:

val a1 = fun _

Do you now understand where your problem is?

少女的英雄梦 2024-12-16 03:10:28

在第一种情况下,您需要编写 fun _ 以避免调用该方法并执行 eta 扩展。

这将起作用:

actions = (fun _) :: actions

如果您不这样做,则会评估 fun

有关更多详细信息,请参阅 方法值) >Scala 语言参考

至于为什么在第二种情况下fun没有被计算,这是因为类型推断可以清楚地得出addAction需要一个函数。顺便说一句,fun的类型从技术上讲是()Unit,而不是Unit,即方法类型,而不是值类型。有关详细信息,请参阅参考中的第 3.3.1 节。

You need to write fun _ in the first case to avoid calling the method and performing eta-expansion instead.

This will work:

actions = (fun _) :: actions

If you don't do this, then fun is evaluated.

For more details, see Section 6.7 (Method Values) of the Scala Language Reference.

As to why fun is not evaluated in the second case, it is because type inference can clearly conclude that addAction expects a function. By the way, the type of fun is technically ()Unit, not Unit, that is, a method type, and not a value type. See Section 3.3.1 in the reference for more.

生来就爱笑 2024-12-16 03:10:28

方法和功能之间存在差异。在您的情况下 actions 是一个函数列表。当编译器知道需要一个函数时(例如 addAction 的情况),它可以自动将方法 fun 转换为函数。现在 :: 也是一个方法,因此编译器也知道它接受函数作为参数。但问题在于右结合运算符 :: 的语法糖。如果您像方法一样调用它: actions.::(fun) 它将编译(尽管我目前无法测试它)。当编写 fun :: actions 时,编译器认为 fun 是一个表达式,因此对其求值,并且由于它“返回”一个 Unit 你得到了你的编译器错误。

编辑

由于我现在有可能检验我的假设(这是错误的),以下是您的选择:

// Usual syntax
actions.::[() => Unit](fun)
actions.::(fun: () => Unit)
actions.::(fun _)
// Operator syntax
(fun: () => Unit) :: actions
(fun _) :: actions

There is a difference between methods and functions. In your case actions is a list of functions. When the compiler knows that a function is required (like in the case of addAction) it can automatically convert a method fun into a function. Now :: is also a method, therefore the compiler also knows that it takes functions as parameters. But the problem is the syntactic sugar of the right-associative operator ::. If you were to call it like a method: actions.::(fun) it will compile (although I can't test it at the moment). When writing fun :: actions the compiler thinks that fun is an expression and therefore evaluates it and since it "returns" a Unit you get your compiler error.

EDIT

Since I now have the possibility to test my hypothesis (which was wrong) here are your options:

// Usual syntax
actions.::[() => Unit](fun)
actions.::(fun: () => Unit)
actions.::(fun _)
// Operator syntax
(fun: () => Unit) :: actions
(fun _) :: actions
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文