Scala:隐式传递一个隐式参数,显式传递另一个。可能吗? 让我们考虑函数:

Scala:隐式传递一个隐式参数,显式传递另一个。可能吗? 让我们考虑函数:,scala,implicit,Scala,Implicit,def foo(隐式a:Int,b:String)=println(a,b) 现在,让我们假设在作用域中有一个隐式字符串和Int(implicit val i1=1),但我们希望将另一个而不是隐式Int(val i2=2)显式传递给foo 我们怎么能做到呢?可能吗? 谢谢你的阅读 显式地调用foo(i2,s1)但是您失去了使用隐式字符串的好处 定义def foo1(a:Int)(隐式b:String)=foo(a,b)并调用foo1(i2) 我所能补充的是: def foo(implicit a

def foo(隐式a:Int,b:String)=println(a,b)

现在,让我们假设在作用域中有一个隐式
字符串
Int
implicit val i1=1
),但我们希望将另一个而不是隐式
Int
val i2=2
)显式传递给
foo

我们怎么能做到呢?可能吗? 谢谢你的阅读

  • 显式地调用
    foo(i2,s1)
    但是您失去了使用
    隐式字符串的好处
  • 定义
    def foo1(a:Int)(隐式b:String)=foo(a,b)
    并调用
    foo1(i2)
  • 我所能补充的是:

    def foo(implicit a: Int, b: String) = println(a, b)
    implicit val i1 = 1
    implicit val s = ""
    val i2 = 2
    foo(i2, implicitly[String])
    

    如果您的方法有许多隐式参数(我有时在项目中有),而您有时只想显式地指定其中一个,并隐式地解析其他参数,那么您可以为我的其他答案中显示的每个其他参数隐式地编写
    。但有时您会更改该方法的签名,或者显式参数位于该参数列表的中间,然后可以使用以下构造来创建更可读的客户端代码:

    假设您有一些类型及其隐式虚拟对象:

    trait I1; implicit object I1 extends I1
    trait I2; implicit object I2 extends I2
    trait I3; implicit object I3 extends I3
    trait I4; implicit object I4 extends I4
    trait I5; implicit object I5 extends I5
    trait I6; implicit object I6 extends I6
    
    现在,您的方法
    foo1
    使用了以下隐式:

    def foo1(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) {
      println(i1, i2, i3, i4, i5, i6)
    }
    
    object Implicits {
      def apply(i4: I4)(implicit i1: I1, i2: I2, i3: I3, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
      implicit def applying(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
    }
    class Implicits(val i1: I1, val i2: I2, val i3: I3, val i4: I4, val i5: I5, val i6: I6)
    
    现在,您通常希望显式指定
    i4:i4
    。所以你写:

    val i4 = new I4 {}
    foo1(implicitly, implicitly, implicitly, i4, implicitly, implicitly)
    

    对于所有隐式,使用以下包装器(应置于方法
    foo2
    的严格范围内,并可能重命名):

    def foo1(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) {
      println(i1, i2, i3, i4, i5, i6)
    }
    
    object Implicits {
      def apply(i4: I4)(implicit i1: I1, i2: I2, i3: I3, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
      implicit def applying(implicit i1: I1, i2: I2, i3: I3, i4: I4, i5: I5, i6: I6) = new Implicits(i1, i2, i3, i4, i5, i6)
    }
    class Implicits(val i1: I1, val i2: I2, val i3: I3, val i4: I4, val i5: I5, val i6: I6)
    
    以及相关的方法
    foo2

    def foo2(implicit implicits: Implicits) = {
      import implicits._
      println(i1, i2, i3, i4, i5, i6)
    }
    
    您现在可以通过以下方式调用
    foo2
    而不是
    foo1

    locally {
      foo2 // using implicit dummy objects I1, ..., I6 from above
      // or with explicit I4:
      val i4 = new I4 {}
      foo2(Implicits(i4))
    }
    

    我知道这是一个老问题,但它可能仍然很有趣。 一种很好的方法是隐式使用默认值:

    scala>def foo(a:Int=implicitly[Int],b:String=implicitly[String])=println(a,b)
    scala>foo()
    (10,boo)
    scala>foo(50)
    (50,boo)
    scala>foo(b=“bar”)
    (10巴)
    
    您可以创建一个新的内部作用域,并在其中定义一个新的
    隐式val
    。这样做的好处是,当您有多个函数调用时,您可以在一个位置覆盖所有函数的一个隐式调用:

    def foo(implicit a:Int, b:String) = println(a,b).
    
    implicit val i = 1
    implicit val s = ""
    
    foo // call with original implicits
    
    {
      implicit val i = 2
    
      foo // call with a new Int implicit
    
      foo // call with a new Int implicit again
    
    }
    

    注意:新隐式必须与原始隐式具有相同的变量名,以便将其隐藏,否则您将得到关于不明确隐式值的编译器错误。

    您知道最疯狂的事情吗?实际上,您甚至可以避免冗余地指定参数类型。换句话说,下面的编译很好:
    foo(i2,隐式)
    ,这里不需要做
    foo(i2,隐式[String])
    如果将来的Scala版本支持在这种情况下使用命名参数,那就太好了,例如
    implicit val a=33;foo(b=“hello”)
    。我想不出哪种情况会有问题。不是真的-在这种情况下,隐式参数必须在方法声明站点的作用域中,而不是在方法调用站点的正常行为中。