我有一个应该返回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仍抱怨。
答案 0 :(得分:70)
我将首先解释Unit
的类型,以防万一。即使你已经知道,其他有同样问题的人也可能不知道。
类型Unit
类似于C或Java中已知的void
。在这些语言中,这意味着“这不会返回任何内容”。但是, Scala中的每个方法都返回一个值。
为了弥合每个返回某些东西的方法之间的差距,并且没有任何有用的东西可以返回,那就是Unit
。此类型是AnyVal
,这意味着它不会在堆上分配,除非它被装箱或是对象上的字段类型。此外,它只有一个值,其字面值为()
。也就是说,你可以这样写:
val x: Unit = ()
这样做的实际效果是,当一个方法“返回”Unit
时,编译器不必实际返回任何值,因为它已经知道该值是什么。因此,它可以通过在字节码级别将它们声明为Unit
来实现返回void
的方法。
无论如何,如果您不想返回任何内容,请返回Unit
。
现在让我们看看给出的代码。 Eclipse说它返回Unit
,事实上,Eclipse是正确的。但是,大多数人实际上会犯错误,让该方法返回AnyVal
或Any
,而不是Unit
。有关示例,请参阅以下代码段:
scala> if (true) 2
res0: AnyVal = 2
那么,发生了什么?好吧,当Scala找到if
语句时,它必须弄清楚它返回的类型是什么(在Scala中,if
语句也返回值)。请考虑以下假设线:
if (flag) x else y
显然,返回的值可以是x
或y
,因此类型必须符合x
和y
的要求。其中一种类型是Any
,因为所有都有Any
类型。如果x
和y
属于同一类型 - 例如Int
- 那么这也是有效的返回类型。由于Scala选择了最具体的类型,因此会选择Int
而不是Any
。
现在,当不有else
语句时会发生什么?即使没有else
语句,条件也可能是错误的 - 否则,使用if
就没有意义了。在这种情况下,Scala所做的是添加else
语句。也就是说,它重写了if
这样的语句:
if (true) 2 else ()
就像我之前说过的那样:如果你没有任何回报,请返回Unit
!这正是发生的事情。由于Int
和Unit
都是AnyVal
,并且AnyVal
比Any
更具体,因此该行返回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
,这就是问题所在。