发现单位:必需国际 为什么错误不明显?

ila*_*ngo 22 scala

我有一个应该返回Int的方法.我试图理解为什么Eclipse不会让我编译它,即使我在if语句中看起来我确实正在返回一个Int.有什么我错过的非常明显吗?在继续编写更多代码之前,我试图理解Scala的这个方面.

这是方法:

def contains1(sfType: TokenType): Int = {
     if (Tokens.KEYWORDS.contains(sfType)) {
      val retVal = TokenTypes.RESERVED_WORD
    }
  }
Run Code Online (Sandbox Code Playgroud)

Eclipse在第2行抱怨---'类型不匹配; 发现:所需单位:Int"

TokenTypes is - public abstract interface org.fife.ui.rsyntaxtextarea.TokenTypes and RESERVED_WORD is - public static final int RESERVED_WORD = 6;
Run Code Online (Sandbox Code Playgroud)

我在这里读过这篇文章:发现:需要单位:Int - 如何纠正这个?并试图在发布之前解决问题,但我仍然不知所措.

编辑:该方法应该返回一个Int,我错误地输入了返回类型.我的问题仍然存在.Eclipse仍然抱怨.

Dan*_*ral 72

我将首先解释什么类型Unit,以防万一.即使你已经知道,其他有同样问题的人可能也不会知道.

类型Unit类似于C或Java中已知的类型void.在那些语言中,这意味着"这不会返回任何东西".但是,Scala中的每个方法都返回一个值.

为了弥合每个返回某些东西的方法之间的差距,并且没有任何有用的东西可以返回,那就是Unit.此类型是一个AnyVal,这意味着它不会在堆上分配,除非它被装箱或是对象上的字段类型.此外,它只有一个值,其字面值().也就是说,你可以这样写:

val x: Unit = ()
Run Code Online (Sandbox Code Playgroud)

这样做的实际效果是,当一个方法"返回"时Unit,编译器不必实际返回任何值,因为它已经知道该值是什么.因此,它可以Unit通过在字节码级别上声明它们来实现返回的方法void.

无论如何,如果你不想退货,你会回来Unit.

现在让我们看看给出的代码.Eclipse说它返回了Unit,事实上,Eclipse是正确的.然而,大多数人实际上使误差具有方法返回的AnyValAny,不是Unit.有关示例,请参阅以下代码段:

scala> if (true) 2
res0: AnyVal = 2
Run Code Online (Sandbox Code Playgroud)

所以发生了什么事?好吧,当Scala找到一个if语句时,它必须弄清楚它返回的类型是什么(在Scala中,if语句也返回值).考虑以下假设线:

if (flag) x else y
Run Code Online (Sandbox Code Playgroud)

显然,返回值将是任一xy,所以类型必须是使得两个xy将适合.一种这样的类型是Any,因为一切都有类型Any.如果两个xy是同一类型的-说Int-那么这也将是一个有效的返回类型.由于斯卡拉挑选最具体的类型,这将挑选IntAny.

现在,当你发生了什么具备的else声明?即使没有else陈述,情况也可能是假的 - 否则,使用就没有意义了if.在这种情况下,Scala所做的是添加一个else语句.也就是说,它重写了这样的if语句:

if (true) 2 else ()
Run Code Online (Sandbox Code Playgroud)

就像我之前说过的那样:如果你没有任何回报,请回来Unit!这正是发生的事情.由于这两个IntUnitAnyVal,而且考虑到AnyVal是不是更具体的Any,该行返回AnyVal.

到目前为止,我已经解释了其他人可能看到的内容,但没有解释问题中特定代码中发生的情况:

if (Tokens.KEYWORDS.contains(sfType)) {
  val retVal = TokenTypes.RESERVED_WORD
}
Run Code Online (Sandbox Code Playgroud)

我们已经看到Scala会像这样重写它:

if (Tokens.KEYWORDS.contains(sfType)) {
  val retVal = TokenTypes.RESERVED_WORD
} else ()
Run Code Online (Sandbox Code Playgroud)

我们看到Scala将在两个可能的结果之间选择最具体的类型.最后,Eclipse告诉使用返回类型Unit,所以唯一可能的解释是这个类型:

  val retVal = TokenTypes.RESERVED_WORD
Run Code Online (Sandbox Code Playgroud)

也是Unit.这恰恰是正确的:在Scala中声明事物的语句具有类型Unit.顺便说一下,做任务.

正如其他人所指出的那样,解决方案是删除赋值并添加一个else语句,同时返回Int:

def contains1(sfType: TokenType): Int =
  if (Tokens.KEYWORDS.contains(sfType)) TokenTypes.RESERVED_WORD
  else -1
Run Code Online (Sandbox Code Playgroud)

(注意:我已经重新格式化了方法,以遵循Scala程序员中更常见的编码风格)


sbe*_*rry 9

我有一种感觉,你需要改变你的方法看起来像下面之一

def contains1(sfType: TokeType): Int = {
  if (Tokens.KEYWORDS.contains(sfType))
    TokenTypes.RESERVED_WORD
  else 
    -1
}

def contains1(sfType: TokenType) = if (Tokens.KEYWORDS.contains(sfType)) TokenTypes.RESERVED_WORD else -1
Run Code Online (Sandbox Code Playgroud)

  • @ilango:您应该将接受的答案更改为 Daniel 的而不是我的。虽然我提供的代码确实有效,但他的回答远优于解释 ** 为什么** 我的代码有效。 (3认同)

pag*_*_5b 7

在scala中没有单一的if陈述

由于当评价必须返回一个值的每个表达式(它可以是一个空值的类型,Unit),则if表达式必须总是以匹配else分支,都必须返回相同的类型,或者在最坏的情况下阶将推断的最常见超类型.

在您的代码中,您Intif分支返回a ,但else缺少分支.

更新

正如其他答案所述:

单个if表达式返回其中唯一的替代方法,对于原始帖子,它是赋值的返回值(),类型为Unit

  • 还要注意,原始问题中表达式的明确真分支也是Unit类型,因为它是val定义,而不是简单表达式.最后,这是我的一个小小的问题,完全不在问题的范围内,原文中的所有括号都是多余的,在我的书中应该删除. (2认同)