简体   繁体   English

函数类型定义中隐式的scala

[英]scala implicit in function type definition

I have following abstract class: 我有以下抽象类:

abstract class FieldProvider[+T: Writes](db: DB)(implicit i: RequestAction, j: ExecutionContext) {}

and following implementations: 以及以下实现:

class LengthProvider extends FieldProvider ...

object LengthProvider extends ((DB) => LengthProvider) {
  def apply(v1: DB): LengthProvider = new LengthProvider(v1)
}

class WidthProvider extends FieldProvider ...

object WidthProvider extends ((DB) => WidthProvider) {
  def apply(v1: DB): WidthProvider = new WidthProvider(v1)
}

The reason why I have these apply methods is because I need following configuration map: 之所以拥有这些apply方法,是因为我需要以下配置图:

val providers: Map[String, ((DB) => FieldProvider)] = Map(
 "length" -> LengthProvider,
 "width"  -> WidthProvider
)

So that I can initialize the providers by the string containing their name: 这样我就可以通过包含提供者名称的字符串来初始化提供者:

providers("length")(db) // returns a new instance of LengthProvider

Now, my problem is that all these providers constructors require two implicit variables. 现在,我的问题是所有这些提供程序构造函数都需要两个隐式变量。 But I don't know how to include it into the function definition (DB) => FieldProvider . 但是我不知道如何将其包含在函数定义(DB) => FieldProvider So, essentially, the apply method signature should be something like (DB)(implicit RequestAction, ExecutionContext) => FieldProvider , but I don't know if there is a correct syntax for what I'm trying to do. 因此,从本质上讲, apply方法签名应该类似于(DB)(implicit RequestAction, ExecutionContext) => FieldProvider ,但是我不知道我尝试执行的语法是否正确。

I could also give up and pass them explicitly: 我也可以放弃并明确传递它们:

object WidthProvider extends ((DB, RequestAction, ExecutionContext) => WidthProvider) {
   def apply(v1: DB, v2: RequestAction, v3: ExecutionContext): WidthProvider = new WidthProvider(v1)(v2,v3)
}

But then I'll have to pass them explicitly elsewhere, instead of providers("length")(db) , I'd have to write providers("length")(db, implicitly[RequestAction], implicitly[ExecutionContext]) , which doesn't feel right. 但是然后我必须将它们显式传递给其他地方,而不是providers("length")(db) ,而必须编写providers("length")(db, implicitly[RequestAction], implicitly[ExecutionContext]) ,感觉不对。

Let's assume FieldProvider has 2 methods that need the implicits. 假设FieldProvider有2个需要隐式的方法。 The more convenient way to avoid duplication is to pass them as constructor level implicit arguments and then all the internal methods in FieldProvider can "share" them. 避免重复的更方便方法是将它们作为构造函数级别的隐式参数传递,然后FieldProvider所有内部方法都可以“共享”它们。

However, this won't help in your current class tree, so to fix this, instead of doing: 但是,这对您当前的类树没有帮助,因此请解决此问题,而不要这样做:

abstract class FieldProvider()(implicit param1: X1..) {
  def test: T = param1.doSomething
}

Simply move the implicit to method level such that you can provide it at a time different than extending the constructor. 只需将隐式移动到方法级别,以便您可以在与扩展构造函数不同的时间提供它。

abstract class FieldProvider() {
  def test()(implicit param1: X1): T = param1.doSomething
}

So, essentially, the apply method signature should be something like (DB)(implicit RequestAction, ExecutionContext) => FieldProvider , but I don't know if there is a correct syntax for what I'm trying to do. 因此,从本质上讲, apply方法签名应该类似于(DB)(implicit RequestAction, ExecutionContext) => FieldProvider ,但是我不知道我尝试执行的语法是否正确。

Note that you might directly get (in a future Scala 2017 version) an implicit function type . 请注意,您可能会直接获得(在将来的Scala 2017版本中) 隐式函数类型

See pull request 1775 , by Odersky himself. 参见奥德斯基本人的拉取请求1775

Let's massage the definition of f1 a bit by moving the last parameter section to the right of the equals sign: 让我们通过将最后一个参数部分移到等号的右边来稍微完善一下f1的定义:

def f1(x: Int) = { implicit thisTransaction: Transaction =>
  thisTransaction.println(s"first step: $x")
  f2(x + 1)
}

The right hand side of this new version of f1 is now an implicit function value. 现在,此新版本的f1的右侧是隐式函数值。
What's the type of this value? 此值的类型是什么?
Previously, it was Transaction => Int , that is, the knowledge that the function has an implicit parameter got lost in the type. 以前是Transaction => Int ,也就是说,该函数具有隐式参数的知识已在类型中丢失。

The main extension implemented by the pull request is to introduce implicit function types that mirror the implicit function values which we have already. pull请求实现的主要扩展是引入隐式函数类型,这些类型反映了我们已经拥有的隐式函数值。
Concretely, the new type of f1 is: 具体来说,新型的f1是:

implicit Transaction => Int

Just like the normal function type syntax A => B , desugars to scala.Function1[A, B] , the implicit function type syntax implicit A => B desugars to scala.ImplicitFunction1[A, B] . 就像普通的函数类型语法A => B ,对scala.Function1[A, B] ,隐式函数类型语法implicit A => B避免对scala.ImplicitFunction1[A, B]
The same holds at other function arities. 其他职能领域也是如此。 With dotty's pull request #1758 merged, there is no longer an upper limit of 22 for such functions. 随着dotty的拉取请求#1758的合并,此类功能的上限不再为22。

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

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