【问题标题】:Returning code block in Scala在 Scala 中返回代码块
【发布时间】:2013-09-08 12:16:01
【问题描述】:

我试图在 Scala 中实现闭包示例,来自 Neal Ford 在 Groovy 中的功能性思维演示文稿。请参阅幻灯片 #43 和 44 https://sea.ucar.edu/sites/default/files/Functional_Thinking.pdf

  def makeCounter : Unit = {
var localVar = 0
return { localVar += 1 }
}

此代码返回一个匿名函数。现在我想通过调用这个匿名函数来增加 localVar。

我有两个问题:
1.如何调用匿名函数?
2. 调用后如何检查localVar的值是否增加?

首先我尝试了这个 -
val c1 = makeCounter()。它抛出以下错误:
错误:Unit类型的makeCounter不带参数

然后我尝试了这个。
val c1 = makeCounter

这没有给出任何错误。只打印 c1: Unit = ()。

那么,
print(c1) print(),而 c1() 给出了同样的错误。

【问题讨论】:

  • "此代码返回一个匿名函数。" - 那你为什么把它的返回类型声明为Unit
  • 我认为他将按名称的 Unit 参数与纯 Unit 混合。

标签: scala functional-programming anonymous-function


【解决方案1】:

首先。不要使用return,它的语义在 Scala 中与在 Java 或 Groovy 中完全不同。

Unit 类型不是匿名函数的同义词。这更像是副作用的迹象。

匿名函数的类型是() => A。在您的情况下,您需要一个不返回任何内容但会导致副作用的函数。所以它的类型应该是() => Unit

让我们看一些代码:

def makeCounter : () => Unit = { 
  var x = 0 
  { () => x = x + 1 } 
}

val counter = makeCounter
counter(); counter(); counter()

太棒了!我们让 makeCounter 给我们一个新的计数器!

只有一个问题。 x 是方法 makeCounter 中的一个局部变量,由于它从未返回,我们看不到它的值!曾经!例如,我们可以从方法中删除x,使其在外部范围内公开。但它不是很实用。相反,让函数返回它:

def makeCounter : () => Int = { // Notice now, instead of Unit we use Int
  var x = 0
  { () => x = x + 1; x } 
}

val counter = makeCounter
println(counter(), counter(), counter())
val counter2 = makeCounter
println(counter2(), counter2(), counter2())

您将看到两次“1,2,3”。每个计数器一次。

【讨论】:

  • 对不起,当我发布我的版本时,我只阅读了should be ()=>Unit。也许您可以从最终答案中删除额外的半号和大括号。 “这是你的最终答案吗?”
  • @som-snytt 实际上,我在视觉上解析您的版本时遇到问题。我什至不知道你可以安排这样的事情。
  • @pedrofurla 如果我不使用 return 它会给出错误 - “错误:块必须以结果表达式结尾,而不是在定义中”。所以我退货了。但是 println(counter()) 仍然没有打印任何东西
  • 我通常不会把它放在一行,除非在 REPL 中输入它。但是比较stackoverflow.com/a/18159362/1296806stackoverflow.com/a/13873899/1296806 的更多解释。
  • 令人困惑的是;。那么,返回v是不是应该是(() => v += 1) ; v?还是应该是 `(() => v += 1 ; v)`,返回一个返回 v 的函数?如果我不测试,我仍然会认为前者就是发生的事情。
【解决方案2】:

我没有看演示文稿,所以我不知道这是功能性思维还是只是通向功能性思维的幻灯片之一,但是:

scala> def f: () => Int = {
     | var v = 0
     | () => v += 1 ; v }
f: () => Int

scala> val g = f
g: () => Int = <function0>

scala> g()
res0: Int = 1

scala> g()
res1: Int = 2

scala> g()
res2: Int = 3

f 返回的函数字面量当然是括号后的所有内容。

【讨论】:

  • 这很好用。但我在这里有一个概念上的疑问。据我了解,这个带有 def f: () => Int 的函数定义意味着它不会接受任何参数并返回一个 Int。但这不是因为这个函数返回的是匿名函数而不是 Int 吗?还是我在这里遗漏了什么?
  • @VarunPaprunia Method f 是无参数的。看看它是如何在没有括号的第 2 行调用的。它返回一个() =&gt; Int。使用 g.apply()g.apply(自动添加括号)或 g()(作为对 apply 的调用)应用值 g
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 2023-01-30
  • 2022-01-22
  • 2011-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多