对这个带有 & 不带 = 的代码片段返回类型感到非常困惑

Posted

技术标签:

【中文标题】对这个带有 & 不带 = 的代码片段返回类型感到非常困惑【英文标题】:Quite confused about this code snippet return types with & without = 【发布时间】:2013-08-24 11:16:12 【问题描述】:
object A extends App 

def closure1(x:Int) = 
  object O 
   def getX = x
   def add(y:Int) = x+y
  
  val foo = O
  foo


def closure2(x:Int) 
  object O 
   def getX = x
   def add(y:Int) = x+y
  
  val foo = O
  foo


println(closure1(4).getClass)
println(closure2(4).getClass)


result:
 $scala A
 class A$O$3$
 void
    为什么返回类型不同? 我真的不关心返回类型。我想调用 getX 并添加 - 我想做像closure1(4).getX 这样的事情 - 这是非法的。我该怎么做?

【问题讨论】:

【参考方案1】:

Scala 有一个不返回任何有趣值的代码的简写符号:省略 = 符号。在 Java 中,这将返回 void,即什么都没有;但在 Scala 中,它实际上是 (),这是名为 Unit 的类型的唯一成员。无论哪种方式,它都是一样的:什么都没有或无意义的占位符。

您想要一个无意义的占位符的原因是,当您编写通用代码时,您宁愿不必以不同的方式处理某些情况。

无论如何:

def f(): Unit = println("Hi")

是一个仅显式返回无内容 () 值的函数(这也是 println 返回的值)。简写是

def f()  println("Hi") 

现在有一个偷偷摸摸的补充,那就是在 Scala 中,与许多 C 派生语言一样,您可以在所做的任何事情中丢弃返回值。当你把它扔掉时,剩下的就是()。 Scala 会在 closure2 上警告您您正在做一些可疑的事情:

<console>:16: warning: a pure expression does nothing in statement position
you may be omitting necessary parentheses
         foo
         ^
defined module A

但仍然会让你这样做(因为历史上预计这会起作用)。

所以,总结一下:

def f 

是一个只返回无内容占位符() 的方法。如果你把它完整地写出来,语法将是

def f: Unit = 

当您尝试返回错误类型的值时,它不会抱怨它会丢弃该值并给您输入Unit,但通常会发出警告:

def f: Unit = 5
def f  5 

(请注意,现在大多数人反对简写形式(现在是 2.10-is-stable),很大程度上是因为在没有明确解释差异的情况下,新用户经常忽略 = 而没有意识到它然后想知道为什么事情不起作用。所以在未来(2.11 或 2.12 弃用?)def f 表单可能不起作用。)

如果你真的想要一个返回值——例如,你想返回你的对象O(顺便说一下,你可以直接这样做,而无需先将它分配给foo),确保你包括=:

def f =  object O  def g = 5 ; O 

scala> f.g
res0: Int = 5

(提示:编译器会抱怨你在这里使用了结构类型。你最好使用trait HasG def g: Int ,然后是object O extends HasG;否则Scala实际上使用反射来调用f.g,原因是我从来没有完全能够跟随。)

【讨论】:

谢谢。我对获取 getX 并添加工作更感兴趣。但是用户Shadowlands回答了那部分(尽管由于某种原因他删除了他的答案!) @kr - 我更明确地将其添加到我的答案中。【参考方案2】:

我认为 Rex 已经解释了原因,您在定义 closure2 时省略了 =,这使 Scala 编译器认为您不想返回任何内容,即使您打算返回 foo

scala> def closure3(x: Int) 
     |   object O 
     |     def getX = x
     |     def add(y: Int) = x + y
     |   
     |   val foo = O
     |   foo
     | 
<console>:17: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
         foo
         ^
closure3: (x: Int)Unit

注意closure3的返回类型是Unit

scala> def closure4(x: Int) = 
     |   object O 
     |     def getX = x
     |     def add(y: Int) = x + y
     |   
     |   O
     | 
closure4: (x: Int)Objectdef getX: Int; def add(y: Int): Int

scala> closure3(2)

closure3(2)什么都不返回,所以你不能调用getX

scala> closure4(2)
res10: Objectdef getX: Int; def add(y: Int): Int = O$2$@a4920bc

【讨论】:

以上是关于对这个带有 & 不带 = 的代码片段返回类型感到非常困惑的主要内容,如果未能解决你的问题,请参考以下文章

处理屏幕旋转上的片段重复(带有示例代码)

安卓。片段 getActivity() 有时返回 null

终于懂了:Delphi重定义消息结构随心所欲,只需要前4个字节是消息编号就行了,跟Windows消息虽然尽量保持一致,但其实相互没有特别大的关系。有了这个,就有了主动,带不带句柄完全看需要。(代码片段

为啥我的 C 代码片段不起作用?简化版可以。为 unsigned long long 传递不带 VA_ARGS 的 args

带有哈希片段的锚未导航到匹配的 id

带有片段的 Android Up 按钮未显示完整片段