简体   繁体   English

使用隐式参数为部分函数定义新的TYPE

[英]Defining new TYPE for partial function with an implicit parameters

I am trying to create a new TYPE that would have a pattern of a partial function. 我正在尝试创建一个具有部分函数模式的新TYPE。 Example: 例:

New Type : 新类型

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

Usage : 用法

def myFunc(str: String, request: HttpServletRequest, response HttpServletResponse) myFunc("", Any, Any) def myFunc(str:字符串,请求:HttpServletRequest,响应HttpServletResponse)myFunc(“”,Any,Any)

For explicitly passed parameters this works really well but I would like to change this type definition so that HttpServletRequest, HttpServletResponse would be passed in implicitly vs. explicitly 对于显式传递的参数,这确实很好用,但是我想更改此类型定义,以便将HttpServletRequest, HttpServletResponse隐式与显式传递。

Expected result : 预期结果

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

I can't find a way how to change the TYPE structure/definition to accomodate the intended pattern, is it possible or is that a language restraint? 我找不到一种方法来更改TYPE结构/定义以适应预期的模式,这是可能的还是语言的限制?

EDIT : 编辑

Usage: 用法:

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")
    }
}

I want the def dashboard to look like: 我希望def dashboard看起来像:

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

EDIT 2 : 编辑2

At the end I went with passing the parameters explicitly as it's impossible with the current version of Scala as explained by @SergGr and @slouc: 最后,我明确地传递了参数,因为对于@SergGr和@slouc所解释的当前版本的Scala,这是不可能的:

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())
    }

}

If I got your question correctly, you want to define a function with implicit parameters. 如果我的问题正确无误,您想使用隐式参数定义一个函数。 This is not possible. 这是不可能的。 Not only is it a language constraint, it's also a logical one. 它不仅是一种语言约束,而且还是一种逻辑约束。 Functions are a mathematical concept and there's no such thing as "implicit parameters" there. 函数是一个数学概念,那里没有所谓的“隐式参数”。 There's no way to provide a subset of parameters, and take the rest "from the scope". 无法提供参数的子集,而其余部分则“从作用域”中获取。

In Scala there's a way to transform a method into a function; 在Scala中,有一种方法可以将方法转换为函数。 the mechanism in question is called eta-expansion. 有问题的机制称为eta扩展。 Given some method fooMethod, then a corresponding function fooFunction can be defined as 给定一些方法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()

Compiler will perform eta-expansion automatically if you provide a method where a function is expected. 如果您提供了需要函数的方法,则编译器将自动执行eta扩展。 In cases where it doesn't do it automatically, you can do it manually: 如果无法自动执行,则可以手动执行:

val fooFunction = fooMethod _

But even that trick fails if you introduce implicit parameters, for reasons stated earlier. 但是,由于前面提到的原因,如果您引入隐式参数,即使该技巧也失败了。

Example: 例:

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

EDIT: 编辑:

Given your edit, this is how I would do it: 鉴于您的编辑,这就是我的做法:

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

You define a route as a function String => Unit , and you define the dashboard as a method which takes implicit request and response and constructs a route for you. 您将路由定义为功能String => Unit ,并将仪表板定义为采用隐式请求和响应并为您构造路由的方法。

EDIT2: 编辑2:

Looks like support for functions with implicit parameters is coming in one of the future Scala versions. 似乎在将来的Scala版本之一中将提供对带有隐式参数的函数的支持。 I don't like this and I won't use it, we have too much implicit hell in Scala even without it, but it's good to know about it so that I don't keep claiming it's impossible :) 我不喜欢这样,我不会使用它,即使没有它,我们在Scala中也会有太多隐含的地狱,但是很高兴知道这一点,这样我就不会一直声称这是不可能的:)

Implicit functions are not supported as of Scala 2.12. 从Scala 2.12开始不支持隐式函数。 It looks like they are planed for one of the later version when Dotty becomes the official Scala compiler 看起来当Dotty成为Scala的官方编译器时,他们计划将其用于更高版本中的一个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM