【问题标题】:Scala Implicit parameters by passing a function as argument To feel the adnvatageScala 隐式参数通过将函数作为参数传递来感受优势
【发布时间】:2013-09-17 16:14:48
【问题描述】:

我尝试感受 Scala 中implicit 参数的优势。 (已编辑:使用匿名函数时的特殊情况。请查看此问题中的链接)

我尝试根据this 帖子进行简单的模拟。在哪里解释了ActionPlayFramework 中的工作原理。这也与that有关。

以下代码就是为此目的:

object ImplicitArguments extends App {

  implicit val intValue = 1 // this is exiting value to be passed implicitly to everyone who might use it

  def fun(block: Int=>String): String = { // we do not use _implicit_ here !
    block(2)  // ?? how to avoid passing '2' but make use of that would be passed implicitly ?
  }

  // here we use _implicit_ keyword to make it know that the value should be passed !
  val result = fun{ implicit intValue =>  {  // this is my 'block'
                         intValue.toString     // (which is anonymous function)
                       }
  }

 println(result) // prints 2

}

我想打印“1”。

如何避免传递魔法“2”但使用隐式定义的“1”?

另请参阅case,我们在定义中不使用implicit,但它存在,因为匿名函数通过implicit 传递。

已编辑: 以防万一,我发布了另一个示例 - 简单模拟 Play'Action 的工作原理:

  object ImplicitArguments extends App {

  case class Request(msg:String)

  implicit val request = Request("my request")

  case class Result(msg:String)

  case class Action(result:Result)
  object Action {
    def apply(block:Request => Result):Action = {
     val result = block(...) // what should be here ??
     new Action(result)
    }
  }

  val action = Action { implicit request =>
    Result("Got request [" + request + "]")
  }

  println(action)

}

【问题讨论】:

  • block(2) 总是将 2 作为 block 的参数。可能你不明白隐式参数的定义,不仅仅是如何“感受优势”。
  • scala tutorial on implicit parameters 的第一行开始“带有隐式参数的方法可以像普通方法一样应用于参数。在这种情况下,隐式标签无效。但是,如果这样的方法缺少其隐式参数的参数,将自动提供此类参数”。如果一个隐式参数可以覆盖你显式传递的东西的行为,那将是各种混乱
  • 我知道我在传递什么,我不奇怪为什么它会打印“2”(阅读时请耐心等待)。有几种情况是如何使用隐式的。请阅读我提供的这两个链接。 @Starge B. 请不要太个人化。我很敏感:)。
  • 关于编辑部分:您的 implicit request 仅将 request 放入本地隐式范围 - 这意味着您现在可以调用接受隐式请求的函数,编译器会将其插入。至于Action.apply body... 在这里你用实际请求调用块....做实际的 IO
  • 说,如果在 apply() 中的 block(...) 中我会隐式使用 [Request],那么我是否使用“隐式请求”都没有关系 - 它将使用请求在某处隐含定义。即使我将自己的请求传递给 Action { myOwnRequest =Result }。困惑我。我想我只需要使用柯里化将我的请求作为第二个参数传递给 apply(...)(implicit request:Request)

标签: scala


【解决方案1】:

隐式不能这样工作。没有魔法。它们只是(通常)隐藏参数,因此在调用函数时会被解析。

有两种方法可以让您的代码正常工作。

您可以修复所有fun 调用的隐式值

def fun(block: Int=>String): String = { 
  block(implicitly[Int]) 
}

implicitly 是 Predef 中定义的函数。再次没有魔法。这是它的定义

def implicitly[A](implicit value: A) = value

但这意味着它会在声明fun而不是每次调用时解析隐含值。

如果你想为不同的调用使用不同的值,你需要添加隐式参数

def fun(block: Int=>String)(implicit value: Int): String = { 
  block(value) 
}

这现在将取决于调用站点的隐式范围。您可以像这样轻松覆盖它

val result = fun{ _.toString }(3)

结果将是"3",因为末尾有明确的3。但是,没有办法神奇地更改声明中的 fun 以从隐式范围中获取值。

我希望你现在能更好地理解隐式,一开始可能有点难以理解。

【讨论】:

  • 我在我的问题底部添加了一个“编辑”。 (仍在阅读您的答案)
  • 好的。隐含地[Int] 这就是我想要的。你认为 Play 的 Action 也隐含使用吗?
  • 没有。 Play 的Action 只是对计算的描述。它使用来自网络的真实请求执行。 Play 的设计非常实用。有迭代器与产生输入的 netty 通信,然后使用 Action 作为函数将请求转换为响应并通过相同的步骤发回。 非常粗略地说。 Play是开源的,你可以在github上浏览github.com/playframework/playframework/blob/master/framework/…
  • 那么在“val action = Action {implicit request =>”中使用“implicit”是没有意义的,因为无论如何它都会因为“implicitly()”方法而隐式使用“Request”代码
【解决方案2】:

似乎对于我问的那个特殊情况,答案可能是这样的:

implicit intValueimplicit requestimplicitly() 一起使用对于接受(匿名)函数的函数仅使用一个 参数并不是一个好主意。

为什么不呢,因为:

说,如果在 block(...)apply() 我会使用 implicitly[Request],那么 我是否使用“隐式请求”并不重要 - 它会使用 在某处隐式定义的请求。即使我会通过我的 自己向Action { myOwnRequest =Result }提出请求。

对于这种特殊情况,最好在第二个参数中使用curryingtwo arguments 和.. - (first)(second) 使用implicit

像这样:

def apply(block:Request => Result)(implicit request:Request):Action2

在此处查看我的little effort 关于此示例/用例的信息。


但是,到目前为止,关于如何通过将(匿名)函数作为参数传递(我最初的问题)来使用 implicit,我没有看到任何好的示例:

fun{ implicit intValue =>  {intValue.toString}

或者那个(更新版本):

val action = Action { implicit request =>
    Result("Got request [" + request + "]")
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 2020-07-15
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多