繁体   English   中英

如何在 scala 中创建尊重隐式转换的内联 function?

[英]How can I create an inline function in scala that respects implicit conversions?

以下面的代码为例:

object Test6 {
  def main(args: Array[String]): Unit = {
    val a = new A
    //works
    takesBTuple(tupleMaker(a, a))
    //does not work, because a becomes an instance of ArrowAssoc[A] instead of ArrowAssoc[B]
    takesBTuple(a->a)
  }

  class A

  class B

  implicit def atob(a: A): B = new B

  def tupleMaker[X, Y](x: X, y: Y): (X, Y) = (x, y)

  def takesBTuple(b: (B, B)): Unit = println("taken")
}

如何获得 TupleMaker 的行为(特别是 w.r.t. 隐式转换),但使用内联 function? 如果对解决方案有帮助,我可以同时修改 class A 和 B,并使用任何中缀运算符(不必是现有的)。

您可以再添加一次转化

implicit def tupleToTuple(a: (A, A)): (B, B) = (atob(a._1), atob(a._2))

更通用的解决方案是

class A
class A1
class B

implicit def atob(a: A): B = new B
implicit def a1tob(a: A1): B = new B

implicit def tupleToTuple[T, X1, Y1, X, Y](t: (X, Y))(implicit 
  ev: T <:< (X1, Y1), 
  ev1: X => X1, 
  ev2: Y => Y1
): T = (t._1, t._2)


val a = new A
val a1 = new A1

takesBTuple(a -> a) // compiles
takesBTuple(a1 -> a1) // compiles
takesBTuple(a -> a1) // compiles 

更简单

implicit def tupleToTuple[X, Y, X1, Y1](t: (X, Y))(implicit 
  ev1: X => X1, 
  ev2: Y => Y1
): (X1, Y1) = (t._1, t._2) 

不起作用,因为首先推断出X (为A )。 所以ev: T <:< (X1, Y1)是首先推断出X1 , Y1的技巧(成为B )。 隐式从左到右解析。

解决这个问题的简单方法是

takesBTuple((a:B) -> a)

否则,您可以定义一个具有->作为方法的特征ConvertibleToB ,然后这将起作用。

val a = new A
val aa = new AA
//all of these work
takesBTuple(tupleMaker(a, a))
takesBTuple(a -> a)
takesBTuple(aa -> a)
takesBTuple(a -> aa)
takesConvertibleToBTuple(a -> a)
takesConvertibleToBTuple(a -> aa)

//Just for demonstration
def takesConvertibleToBTuple(t: (ConvertibleToB, ConvertibleToB)): Unit = println("took " + t)
trait ConvertibleToB {
  def convertToB: B
  def ->(b: B): (B, B) = (convertToB, b)
  def ->(a: this.type): (this.type, this.type) = (this, a)
}

class A extends ConvertibleToB {
  override def convertToB: B = new B
}

class AA extends ConvertibleToB {
  override def convertToB: B = new B
}

implicit def makeB(c: ConvertibleToB): B = c.convertToB

您需要导入的唯一隐式 def 是makeB 不过,我不知道这是否是您想要的,或者对您是否实用,尤其是如果您不希望将(A, AA)类型的元组转换为(B, B)

链接到 Scastie: https://scastie.scala-lang.org/pPuzw0sSQfKlglfT0a3Rrw

暂无
暂无

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

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