如何通过 apply() 将协变可变参数传递给采用相同类型的协变可变参数的函数

发布于 2024-10-21 01:15:36 字数 1095 浏览 3 评论 0原文

请原谅任何错误的术语;我对 Scala 比较陌生。我会根据需要尽力澄清:)

我想设置一个函数[T <: Closeable, R],参数为T*,函数(T*)=>R,然后使用T* varargs调用该函数这是争论。这在代码中可能更清楚:

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...
        }
    }
}    

不幸的是,usingva 版本无法编译,我对如何最好地完成可变参数贷款结构感到有些茫然。

非常感谢任何和所有的建议,ty。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

望笑 2024-10-28 01:15:36

您必须在参数后面放置一个 :_* 来告诉编译器这不是一个单独的参数,而是整个参数序列:

action(closeables :_*)

编辑评论中的第二个问题:< /em> 对于您的具体问题,不使用 varargs 可能是更好的选择,但直接将生成的 Seq 与部分函数结合使用:

def usingva[T <: Closeable, R](closeables: T*)(action: PartialFunction[Seq[T], R]): Unit = {
  try {            
    action(closeables) 
  } 
  finally {
    //...close everything... 
  } 
}

然后可以像这样使用:

usingva(new FileWriter(file), new FileWriter(file) {
   case Seq(fw1,fw2) => ... // You can use fw1 and fw2 seperately here
}

不幸的是没有办法使此类型安全(即在编译时检查参数数量是否与函数匹配),但为所有数量的参数创建“使用”函数除外,因为 scala 中的类型级别不支持整数。与元组相同的问题...这就是为什么实际上有类 Tuple1Tuple2、...、Tuple22 (是的...它们停在22)

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)

‘画卷フ 2024-10-28 01:15:36

您需要将可变参数转换为类型系统的 Seq(Scala 内部所做的)。

action :  Seq[T] => R

You need to convert the varargs into a Seq for the type system (what Scala does internally).

action :  Seq[T] => R
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文