27

Intを返すことになっているメソッドがあります。ifステートメント内で実際にIntを返しているように見えても、Eclipseでこれをコンパイルできない理由を理解しようとしています。私が見逃しているものが非常に明白にありますか?さらにコードを書く前に、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;

私はここでこの投稿を読みました:見つかった:必要な単位:Int-これを修正する方法は?投稿する前に問題を解決しようとしましたが、私はまだ途方に暮れています。

編集:メソッドはIntを返すことになっていますが、returntypeを間違って入力しました。私の問題は同じままです。Eclipseはまだ文句を言います。

4

4 に答える 4

88

I'll first explain what type Unit is, just in case. Even if you know already, other people having the same kind of problem might well not know it.

Type Unit is similar to what is known in C or Java as void. In those languages, that means "this does not return anything". However, every method in Scala returns a value.

To bridge the gap between every method returning something and not having anything useful to return, there's Unit. This type is an AnyVal, which means it isn't allocated on the heap, unless it gets boxed or is the type of a field on an object. Furthermore, it has only one value, whose literal is (). That is, you could write this:

val x: Unit = ()

The practical effect of this is that, when a method "returns" Unit, the compiler doesn't have to actually return any value, since it already knows what that value is. Therefore, it can implement methods returning Unit by declaring them, on the bytecode level, as being void.

Anyway, if you don't want to return anything, you return Unit.

Now let's look at the code given. Eclipse says it returns Unit, and, in fact, Eclipse is correct. However, most people would actually make the error of having that method return AnyVal or Any, not Unit. See the following snippet for an example:

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

So, what happened? Well, when Scala finds an if statement, it has to figure out what is the type returned by it (in Scala, if statements return values as well). Consider the following hypothetical line:

if (flag) x else y

Clearly, the returned value will be either x or y, so the type must be such that both x and y will fit. One such type is Any, since everything has type Any. If both x and y were of the same type -- say, Int -- then that would also be a valid return type. Since Scala picks the most specific type, it would pick Int over Any.

Now, what happens when you don't have an else statement? Even in the absence of an else statement, the condition may be false -- otherwise, there would be no point in using if. What Scala does, in this case, is to add an else statement. That is, it rewrites that if statement like this:

if (true) 2 else ()

Like I said before: if you do not have anything to return, return Unit! That is exactly what happens. Since both Int and Unit are AnyVal, and given that AnyVal is more specific than Any, that line returns AnyVal.

So far I have explained what others might have seen, but not what happens in that specific code in the question:

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

We have seen already that Scala will rewrite it like this:

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

We have also seen that Scala will pick the most specific type between the two possible results. Finally, Eclipse tells use that the return type is Unit, so the only possible explanation is that the type of this:

  val retVal = TokenTypes.RESERVED_WORD

is also Unit. And that's precisely correct: statements that declare things in Scala have type Unit. And, so, by the way, do assignments.

The solution, as others have pointed out, is to remove the assignment and add an else statement also returning an Int:

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

(note: I have reformatted the method to follow the coding style more common among Scala programmers)

于 2013-01-09T02:30:53.843 に答える
10

次のように方法を変更する必要があると思います

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
于 2013-01-07T22:47:05.980 に答える
8

Scalaには単一のifステートメントはありません

評価される各式は値を返す必要があるため(タイプは空の値にすることができますUnit)、if式は常にブランチと一致する必要がありelse、両方が同じタイプを返す必要があります。そうしないと、最悪の場合、scalaが最も一般的なものを推測します。スーパータイプ。

コードでブランチIntからaを返しますifが、elseブランチがありません。

更新しました

他の回答で正しく述べられているように:

単一のif式は、その中の唯一の選択肢を返します。これは、元の投稿の場合、()タイプの割り当ての戻り値です。Unit

于 2013-01-07T22:46:36.730 に答える
4

Eclipseは、「if」ブロックがfalseの場合、つまり、Tokens.KEYWORDS.contains(sfType)であるfalse場合、戻り型は実際にになると考えUnitています。これが問題です。

于 2013-01-09T02:39:27.057 に答える