¿Por qué este límite de tipo estructural no funciona como se esperaba?
-
24-10-2019 - |
Pregunta
Estoy tratando de escribir un método de ayuda simple que reciba algo que puede cerrarse y alguna función que reciba la primera y asegura que el "cierre" esté cerrado después de ejecutar la función.
Por ejemplo, quiero usarlo así:
closing(new FileOutputStream("/asda"))(_.write("asas"))
Mi impl es
object Helpers {
def closing[T <: { def close }](closeable: T)(action: T => Unit): Unit =
try action apply closeable finally closeable close
}
Pero al intentar compilar esta simple prueba:
object Test {
import Helpers._
closing(new FileOutputStream("/asda"))(_.write("asas"))
}
El compilador se queja con:
Argumentos de tipo inferido [java.io.fileOutputStream] No se ajuste a los límites de parámetros de tipo de cierre del método [t <: anyref {def cerrador: unidad}
¿Alguna idea por qué?
Solución
Necesitas escribir
def closing[T <: { def close() }]
Hay una diferencia en Scala entre métodos con paréntesis y métodos vacíos sin paréntesis.
Otros consejos
Los límites de tipo son complicados. En particular, Scala realiza un seguimiento del número de listas de parámetros además de los parámetros en sí. ¡Prueba esto!
class A { def f = 5 }
class B { def f() = 5 }
class C { def f()() = 5 }
def useA[X <: { def f: Int }](x: X) = x.f
def useB[X <: { def f(): Int }](x: X) = x.f
def useC[X <: { def f()(): Int}](x: X) = x.f
useA(new A) // This works, but what other combinations do?
En tu caso, quieres
def closing[T <: { def close() }] ...
PD: Si realmente planeas usar esto mucho, probablemente también deberías jugar con
class D extends B { override def f = 6 }
class E extends A { override def f() = 6 }
y ver cuál use
Necesita usar en cada caso.