我希望能够将一个函数传递给一个类,使得函数总是返回一个布尔值,但参数的数量可以是变量。
这实际上就是我现在正在使用的:
/**
* Template class for any SecureSocial SecuredAction.
*/
class SomeAction[T](
isSuccessful: (SecuredRequest[AnyContent], T) => Boolean,
success: Result,
failure: Result) extends SecureSocial {
def toReturn = SecuredAction(WithProvider("google")) {
implicit request => if (isSuccessful(request)) success else failure
}
}
我希望isSuccessful
参数是一个函数,它至少需要一个类型SecuredRequest[AnyContent]
的参数和一个零或多个参数。有时我会传入一个只需要request
对象的函数,有时候我会传入一个需要request
对象和其他参数的函数。
在seeing this answer之后,我看着cur {,the practice of transforming a multiple-argument function into a single-argument function that will return a function if any more arguments are needed。这听起来像是可以解决我的问题,但在阅读了difference between partially applied functions and currying后,我开始想不到了?看起来仍有一定数量的最终参数...
我认为成功的讨论会如此:
class SomeAction[T](
isSuccessful : ((SecuredRequest[AnyContent])(T) => Boolean) , // ERROR
... ) ... { ... }
这绝对不是正确的语法。
或
class SomeAction[T](
isSuccessful : (SecuredRequest[AnyContent] => Boolean) ,
... ) ... { ... }
在isSuccessful
中对toReturn
执行某些操作以取消传递的函数。
(SecuredRequest[AnyContent] => Boolean)
类型的功能,但在isSuccessful(request)
来电时是否有某种不确定性?感谢阅读;我想我只是在寻找无关紧要的例子。
答案 0 :(得分:1)
如果您的方法f
类型为(A*)B
,那么eta-expanded f _
只是Seq[A] => B
。
在f
内部,重复的参数无论如何都有Seq[A]
类型,所以它是有道理的。
有一张着名的票:
https://issues.scala-lang.org/browse/SI-4176
它以立即弃用的选项-Yeta-expand-keeps-star而闻名。
以下是一个方法的示例,该方法采用箭头左侧带星形的函数并调用它。
因此,如果“any-arity”表示“任意数量的T
s”,例如类型T = (String, String)
,那么varargs就足够了。
object Test extends App {
def f(g: (Int*) => Int) = g(1,2,3)
def sum(is: Int*) = is.sum
Console println f(sum _)
def f2(g: (Int*) => Int, h: =>Seq[Int]): Int = g(h: _*)
Console println f2(sum _, List(1,2,3))
def f3(g: (Int*) => Int, is: Int*): Int = g(is: _*)
Console println f3(sum _, 1,2,3)
}
答案 1 :(得分:1)
如果函数采用可变数量的参数,则可以执行此操作。这是必要的,因为他们事先并不知道动作会给他们多少个参数。正如其他人所提到的,可变参数函数被转换为函数,其最后一个参数是一个序列。所以你可以这样做:
case class Action[T](f: (String, Seq[T]) => Boolean);
def testfn(s: String, args: Int*): Boolean = true;
new Action[Int](testfn _);
如果你需要你的函数来表明它们的参数数量错误,你可以让它们返回Option
并为每个arities添加一些辅助函数,比如
case class Action[T](f: (String, Seq[T]) => Option[Boolean]);
然后,您可以为不同的arities提供帮助,将“正常”函数转换为可变参数,如果给出错误数量的参数,则返回None
:
// for 1 argument functions:
def toVar[T](f: (String, T) => Boolean)(s: String, xs: Seq[T]): Option[Boolean] =
Some(xs).collect({ case Seq(x1) => f(s, x1) });
// for 2 argument functions:
def toVar[T](f: (String, T, T) => Boolean)(s: String, xs: Seq[T]): Option[Boolean] =
Some(xs).collect({ case Seq(x1, x2) => f(s, x1, x2) });
def testfn(s: String, x1: Int, x2: Int): Boolean =
(x1 == x2);
new Action[Int](toVar(testfn _));
如果为toVar
创建了专门用于调用Action
和主要构造函数的不同arities的构造函数,您甚至可以避免使用toVar
。
答案 2 :(得分:0)
知道了。
/**
* Template class for any SecureSocial SecuredAction that involves using user information.
* @param isSuccessful: SecuredRequest[AnyContent] => Boolean
*/
class UserReqAction(
isSuccessful: (SecuredRequest[AnyContent] => Boolean),
success: Result, failure: Result) extends SecureSocial {
def toReturn = SecuredAction(WithProvider("google")) {
implicit request => if (isSuccessful(request)) success else failure
}
}
/**
* Template class for any SecureSocial SecuredAction that does not use user information.
* @param isSuccessful: SecuredRequest[AnyContent] => Boolean
*/
class UserNotReqAction(isSuccessful: () => Boolean,
success: Result, failure: Result) extends SecureSocial {
def toReturn = SecuredAction(WithProvider("google")) {
implicit request => if (isSuccessful()) success else failure
}
}
// not curried example
def makeNewThing = new UserReqAction(
userOp.createThing,
Ok(Json.toJson(Json.obj("success" -> true, "msg" -> "Thing successfully created"))),
BadRequest("failed to create Thing")).toReturn
// curried example
def editThing(param1: _, param2: _, etc) = new UserReqAction(
userOp.updateThing(param1, param2, etc), // this is the currying
Ok(Json.toJson(Json.obj("success" -> true, "msg" -> "Thing successfully edited"))),
BadRequest("failed to edit Thing")).toReturn
def updateThing(param1: _, param2: _, etc)(request: SecuredRequest[AnyContent] ) {...}