How to pass co-variant varargs through apply() to a function that takes co-variant varargs of the same type
Pardon any mistaken terminology; I am relatively new to Scala. I will endeavor to clarify as necessary :)
I want to setup a function[T <: Closeable, R], with parameters T*, function (T*)=>R, then invoke the function with the T* varargs as it's arguments. This is probably much clearer in code:
import java.io.Closeable
object Loans {
/**
* works fine, yay!
开发者_开发问答 * Eg: using(new FileWriter(file)) { fw => ...use fw... }
*/
def using[T <: Closeable, R](c: T)(action: T => R): R = {
try {
action(c)
} finally {
if (null != c) c.close
}
}
/**
* Won't compile:
* type mismatch;
* found: closeables.type (with underlying type T*)
* required: T possible cause: missing arguments for method or constructor
*
* Intended usage is:
*
* usingva(new FileWriter(f), new OtherCloseable()) { ... }
*/
def usingva[T <: Closeable, R](closeables: T*)(action: (T*) => R): Unit = {
try {
action.apply(closeables)
} finally {
//...close everything...
}
}
}
Unfortunately the usingva version doesn't compile and I am at somewhat of a loss for how best to accomplish the varargs loan structure.
Any and all advice much appreciated, ty.
You will have to put a :_*
behind the parameter to tell the compiler that this is not one single argument but the entire seq of arguments:
action(closeables :_*)
Edit concerning your second question in the comment: For your specific problem it might be a better choice not to use varargs but the resulting Seq
directly in combination with a partial function:
def usingva[T <: Closeable, R](closeables: T*)(action: PartialFunction[Seq[T], R]): Unit = {
try {
action(closeables)
}
finally {
//...close everything...
}
}
this can then be used like this:
usingva(new FileWriter(file), new FileWriter(file) {
case Seq(fw1,fw2) => ... // You can use fw1 and fw2 seperately here
}
There is unfortunately no way to make this typesafe (ie. check that number of parameters match the function at compile time) except for creating using
functions for all numbers of parameters because there is no integer support on type level in scala. Same problem like tuples... that is why there are actually classes Tuple1
, Tuple2
, ... , Tuple22
(Yes... they stop at 22)
You need to convert the varargs into a Seq for the type system (what Scala does internally).
action : Seq[T] => R
精彩评论