scala - obra - Unidad encontrada: requerida Int. ¿Por qué el error no es obvio?
resumen de la obra no es obvio (4)
Eclipse piensa que si el bloque "si" es falso, es decir, Tokens.KEYWORDS.contains(sfType)
es false
, entonces el tipo de retorno será de hecho Unit
, que es el problema.
Tengo un método que se supone que devuelve un Int. Estoy tratando de entender por qué Eclipse no me permite compilar esto, a pesar de que me parece evidente dentro de la afirmación if si estoy devolviendo un Int. ¿Hay algo que me falta muy obvio? Estoy tratando de entender este aspecto de Scala antes de proceder a escribir más código.
Aquí está el método:
def contains1(sfType: TokenType): Int = {
if (Tokens.KEYWORDS.contains(sfType)) {
val retVal = TokenTypes.RESERVED_WORD
}
}
Eclipse se queja en la línea 2 --- ''tipo desajuste; encontrado: Unidad requerida: Int "
TokenTypes is - public abstract interface org.fife.ui.rsyntaxtextarea.TokenTypes and RESERVED_WORD is - public static final int RESERVED_WORD = 6;
He leído este post aquí: encontrado: Unidad requerida: Int - ¿Cómo corregir esto? e intenté resolver el problema antes de publicarlo, pero todavía estoy perdido.
Edición: se supone que el método devuelve un Int y yo escribí incorrectamente el tipo de retorno. Mi problema sigue siendo el mismo. Eclipse todavía se queja.
En Scala no hay una sola sentencia if
.
Dado que cada expresión cuando se evalúa debe devolver un valor (puede ser un valor vacío, de tipo Unit
), la expresión if
debe coincidir siempre con una rama else
, y ambas deben devolver el mismo tipo, o en el peor de los casos, scala deducirá El supertipo más común.
En su código, devuelve un Int
de la rama if
, pero falta la rama else
.
actualizado
Como se indica correctamente en otras respuestas:
el solo if
expresión devuelve la única alternativa dentro de ella, que para la publicación original es el valor de retorno de una asignación, que es ()
de tipo Unit
Primero explicaré qué tipo de Unit
es, por si acaso. Incluso si ya lo sabe, otras personas que tienen el mismo tipo de problema podrían no saberlo.
Tipo de Unit
es similar a lo que se conoce en C o Java como void
. En esos idiomas, eso significa "esto no devuelve nada" . Sin embargo, cada método en Scala devuelve un valor .
Para cerrar la brecha entre cada método que devuelve algo y que no tiene nada útil que devolver, existe la Unit
. Este tipo es AnyVal
, lo que significa que no se asigna en el montón, a menos que esté encuadrado o sea el tipo de campo en un objeto. Además, tiene un solo valor, cuyo literal es ()
. Es decir, podrías escribir esto:
val x: Unit = ()
El efecto práctico de esto es que, cuando un método "devuelve" una Unit
, el compilador no tiene que devolver ningún valor, ya que ya sabe cuál es ese valor. Por lo tanto, puede implementar métodos que devuelven la Unit
al declararlos, en el nivel de bytecode, como void
.
De todos modos, si no quieres devolver nada, devuelves Unit
.
Ahora veamos el código dado. Eclipse dice que devuelve la Unit
y, de hecho, Eclipse es correcto. Sin embargo, la mayoría de las personas realmente cometen el error de que el método devuelva AnyVal
o Any
, no Unit
. Vea el siguiente fragmento de código para un ejemplo:
scala> if (true) 2
res0: AnyVal = 2
¿Entonces qué pasó? Bueno, cuando Scala encuentra una sentencia if
, tiene que averiguar cuál es el tipo que devuelve (en Scala, if
sentencias también devuelven valores). Considera la siguiente línea hipotética:
if (flag) x else y
Claramente, el valor devuelto será x
o y
, por lo tanto, el tipo debe ser tal que tanto x
como y
se ajusten. Uno de estos tipos es Any
, ya que todo tiene type Any
. Si tanto x
como y
fueran del mismo tipo, por ejemplo, Int
, entonces también sería un tipo de retorno válido. Dado que Scala elige el tipo más específico, escogería Int
sobre Any
.
Ahora, ¿qué pasa cuando no tienes else
declaración? Incluso en ausencia de una declaración else
, la condición puede ser falsa; de lo contrario, no tendría sentido utilizar if
. Lo que Scala hace, en este caso, es agregar una declaración else
. Es decir, reescribe esa afirmación como esta:
if (true) 2 else ()
Como dije antes: si no tiene nada que devolver, devuelva la Unit
! Eso es exactamente lo que sucede. Dado que tanto Int
como Unit
son AnyVal
, y dado que AnyVal
es más específico que Any
, esa línea devuelve AnyVal
.
Hasta ahora he explicado lo que otros pudieron haber visto, pero no lo que sucede en ese código específico en la pregunta:
if (Tokens.KEYWORDS.contains(sfType)) {
val retVal = TokenTypes.RESERVED_WORD
}
Ya hemos visto que Scala lo reescribirá así:
if (Tokens.KEYWORDS.contains(sfType)) {
val retVal = TokenTypes.RESERVED_WORD
} else ()
También hemos visto que Scala elegirá el tipo más específico entre los dos resultados posibles. Finalmente, Eclipse dice que el tipo de retorno es Unit
, por lo que la única explicación posible es que el tipo de esto:
val retVal = TokenTypes.RESERVED_WORD
También es Unit
. Y eso es precisamente correcto: las declaraciones que declaran cosas en Scala tienen tipo de Unit
. Y, así, por cierto, hacer asignaciones.
La solución, como han señalado otros, es eliminar la asignación y agregar una declaración else
que también devuelva un Int
:
def contains1(sfType: TokenType): Int =
if (Tokens.KEYWORDS.contains(sfType)) TokenTypes.RESERVED_WORD
else -1
(nota: he reformateado el método para seguir el estilo de codificación más común entre los programadores de Scala)
Tengo la sensación de que necesita cambiar su método para parecerse a uno de los siguientes
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