使用隐式参数

时间:2018-01-25 14:16:44

标签: scala

我正在尝试创建一个具有部分功能模式的新TYPE。例如:

新类型

type RouteFunc = (String, HttpServletRequest, HttpServletResponse) => Unit

用法

def myFunc(str:String,request:HttpServletRequest,response HttpServletResponse) myFunc(“”,Any,Any)

对于显式传递的参数,这非常有效,但我想更改此类型定义,以便隐式传递HttpServletRequest, HttpServletResponse与显式传递

预期结果

def myFunc(str: String)(implicit request: HttpServletRequest, response HttpServletResponse)

我找不到如何更改TYPE结构/定义以适应预期模式的方法,是否可能或是语言限制?

修改

用法:

object Routes{
    type RouteFunc = (String, HttpServletRequest, HttpServletResponse) => Unit

    val routes = Map[String, RouteFunc](
        "/data" -> DataSets.dashboard
    )

    def evaluateRoute()(implicit request: HttpServletRequest, response: HttpServletResponse) = {
        val path = request.getPathInfo

        val route = routes(path)
        route(path, request, response)
    }
}
object DataSets{
    def dashboard(path: String, request: HttpServletRequest, response: HttpServletResponse) = {
        response.setContentType("text/html")
        response.setCharacterEncoding("UTF-8")

        response.getWriter.write("Hello World")
    }
}

我希望def dashboard看起来像:

def dashboard(path: String)(implicit request: HttpServletRequest, response: HttpServletResponse)

编辑2

最后,我明确地传递了参数,因为使用当前版本的Scala是不可能的,正如@SergGr和@slouc所解释的那样:

import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
import controllers.data._
import Routes._

class RoutingController() extends JettyHttpServlet {

    type RouteFunc = (String, HttpServletRequest, HttpServletResponse) => Unit
    type HttpRequest = String
    type Path = String

    val routes = Map[(String, HttpRequest), RouteFunc](
        (GET,       "/data")                -> Data.dashboard,
        (GET,       "/assets/*")            -> Assets.getAsset

    )

    override def Get()(implicit request: HttpServletRequest, response: HttpServletResponse): Unit = {
        val path = request.getPathInfo
        val pathTerms = path.split("/")
        val getPaths = routes.filter(_._1._1 == request.getMethod.toUpperCase)

        val filteredList = getPaths.flatMap{
            route =>
                if(route._1._2 == path){
                    Option(route)
                }else {
                    val s = route._1._2.split("/")

                    if(route._1._2.startsWith("/assets")){
                        Option(route)
                    }else
                        None
                }
        }.toSeq

        filteredList.head._2(path, request, response)
    }

}

----------------------

import jetty.Routes
import jetty.Responses._

object Data {

    import javax.servlet.http.{HttpServletRequest, HttpServletResponse}

    def dashboard(path: String, eq: HttpServletRequest, qw: HttpServletResponse): Unit = {
            implicit val s = eq
            implicit val r = qw
        Ok(Routes.html, views.html.data.dashboard.render("Dashboard").toString())
    }

}

2 个答案:

答案 0 :(得分:0)

如果我正确地得到了你的问题,你想要用隐式参数定义一个函数。这是不可能的。它不仅是一种语言约束,而且也是一种逻辑约束。函数是一个数学概念,并且没有"隐含参数"那里。没有办法提供参数的子集,并从范围"中取出剩下的参数。

在Scala中,有一种方法可以将方法转换为函数;所讨论的机制称为eta-expansion。给定一些方法fooMethod,然后可以将相应的函数fooFunction定义为

def fooMethod(i: Input): Output
val fooFunction: Input => Output = (i: Input) => fooMethod(i)

// or

def fooMethod(i1: Input1, i2: Input2): Output
val fooFunction: Input1 => Input2 => Output = (i1: Input1) => (i: Input2) => fooMethod(i1, i2)

// or

def fooMethod(): Output
val fooFunction: Unit => Output = () => fooMethod()

如果您提供预期功能的方法,编译器将自动执行eta-expansion。如果它没有自动执行,您可以手动执行:

val fooFunction = fooMethod _

但是,如果引入隐式参数,即使这个技巧也会失败,原因如前所述。

示例:

trait HttpServletRequest
trait HttpServletResponse

type RouteFunc = String => (HttpServletRequest, HttpServletResponse) => Unit

implicit val request = new HttpServletRequest {}
implicit val response = new HttpServletResponse {}

def myMethod1(str: String)(request: HttpServletRequest, response: HttpServletResponse) = println("1")
def myMethod2(str: String)(implicit request: HttpServletRequest, response: HttpServletResponse) = println("2")

val myFunc1: RouteFunc = myMethod1 _ // compiles fine
val myFunc2: RouteFunc = myMethod2 _ // nope

修改

鉴于你的编辑,我就是这样做的:

trait HttpServletRequest
trait HttpServletResponse

object Routes {

  implicit val request = new HttpServletRequest {}
  implicit val response = new HttpServletResponse {}

  type RouteFunc = String => Unit
  val routes = Map[String, RouteFunc]("/data" -> DataSets.dashboard())
}

object DataSets {

  def dashboard()(implicit request: HttpServletRequest, response: HttpServletResponse): RouteFunc =
    (path: String) => {
      // impl of dashboard, uses request and response
  }
}

您将路径定义为函数String => Unit,并将仪表板定义为采用隐式请求和响应并为您构建路径的方法。

<强> EDIT2:

看起来对具有隐式参数的函数的支持将来自未来的Scala版本之一。我不喜欢这样,我不会使用它,即使没有它,我们在Scala中也有太多隐含的地狱,但是知道这件事是很好的,所以我不能保持声称这是不可能的:)

答案 1 :(得分:0)

Scala 2.12不支持隐式函数。当Dotty成为官方Scala编译器

时,看起来它们是planed以后的版本之一