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

时间:2013-01-07 22:39:35

标签: scala

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

以下是方法:

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

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

TokenTypes is - public abstract interface org.fife.ui.rsyntaxtextarea.TokenTypes and RESERVED_WORD is - public static final int RESERVED_WORD = 6;

我在这里阅读了这篇文章:found: Unit required: Int - How to correct this?并尝试在发布之前解决问题,但我仍然处于亏损状态。

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

4 个答案:

答案 0 :(得分:70)

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

类型Unit类似于C或Java中已知的void。在这些语言中,这意味着“这不会返回任何内容”。但是, Scala中的每个方法都返回一个值

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

val x: Unit = ()

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

无论如何,如果您不想返回任何内容,请返回Unit

现在让我们看看给出的代码。 Eclipse说它返回Unit,事实上,Eclipse是正确的。但是,大多数人实际上会犯错误,让该方法返回AnyValAny,而不是Unit。有关示例,请参阅以下代码段:

scala> if (true) 2
res0: AnyVal = 2

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

if (flag) x else y

显然,返回的值可以是xy,因此类型必须符合xy的要求。其中一种类型是Any,因为所有都有Any类型。如果xy属于同一类型 - 例如Int - 那么这也是有效的返回类型。由于Scala选择了最具体的类型,因此会选择Int而不是Any

现在,当else语句时会发生什么?即使没有else语句,条件也可能是错误的 - 否则,使用if就没有意义了。在这种情况下,Scala所做的是添加else语句。也就是说,它重写了if这样的语句:

if (true) 2 else ()

就像我之前说过的那样:如果你没有任何回报,请返回Unit!这正是发生的事情。由于IntUnit都是AnyVal,并且AnyValAny更具体,因此该行返回AnyVal

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

if (Tokens.KEYWORDS.contains(sfType)) {
  val retVal = TokenTypes.RESERVED_WORD
}

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

if (Tokens.KEYWORDS.contains(sfType)) {
  val retVal = TokenTypes.RESERVED_WORD
} else ()

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

  val retVal = TokenTypes.RESERVED_WORD

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

正如其他人所指出的那样,解决方案是删除作业并添加else语句并返回Int

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

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

答案 1 :(得分: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

答案 2 :(得分:7)

在scala中没有单if个语句

由于每个表达式在计算时必须返回一个值(它可以是类型为Unit的空值),if表达式必须始终与else分支匹配,并且两者都必须返回相同的类型,或者在最坏的情况下,scala将推断出最常见的超类型。

在您的代码中,您从Int分支返回if,但缺少else分支。

更新

正如其他答案所述:

单个if表达式返回其中唯一的替代方案,原始帖子是作业的返回值,()类型为Unit

答案 3 :(得分:4)

Eclipse认为如果“if”块为false,即Tokens.KEYWORDS.contains(sfType)false,则返回类型确实为Unit,这就是问题所在。