Why this structural type bound does not work as expected?
-
24-10-2019 - |
문제
I'm trying to write a simple helper method that receives something that can be closed and some function which receives the former and ensures the "closeable" is closed after executing the function.
For example, I want to use it like this:
closing(new FileOutputStream("/asda"))(_.write("asas"))
My impl is
object Helpers {
def closing[T <: { def close }](closeable: T)(action: T => Unit): Unit =
try action apply closeable finally closeable close
}
But when trying to compile this simple test:
object Test {
import Helpers._
closing(new FileOutputStream("/asda"))(_.write("asas"))
}
The compiler complains with:
inferred type arguments [java.io.FileOutputStream] do not conform to method closing's type parameter bounds [T <: AnyRef{def close: Unit}]
Any ideas why?
해결책
You need to write
def closing[T <: { def close() }]
there is a difference in Scala between methods with empty parentheses and methods without parentheses at all.
다른 팁
Type bounds are tricky. In particular, Scala keeps track of the number of parameter lists in addition to the parameters themselves. Try these out!
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?
In your case, you want
def closing[T <: { def close() }] ...
P.S. If you really plan on using this a lot, you probably ought also play with
class D extends B { override def f = 6 }
class E extends A { override def f() = 6 }
and see which use
you need to use in each case.