如何在 Scala 中创建一个支持隐式转换的内联函数?
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。隐式转换)?我可以同时修改 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
您需要导入的唯一隐式定义是 makeB
。不过,我不知道这是否是您想要的,或者它是否对您实用,特别是如果您不希望将 (A, AA)
类型的元组转换为 (B, B)
Link 给斯卡斯蒂:https://scastie.scala-lang.org/pPuzw0sSQfKlglfT0a3Rrw
以如下代码为例:
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。隐式转换)?我可以同时修改 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
您需要导入的唯一隐式定义是 makeB
。不过,我不知道这是否是您想要的,或者它是否对您实用,特别是如果您不希望将 (A, AA)
类型的元组转换为 (B, B)
Link 给斯卡斯蒂:https://scastie.scala-lang.org/pPuzw0sSQfKlglfT0a3Rrw