需要两个隐式参数之一的 Scala 方法
Scala method that needs either one of two implicit parameters
如果我可以创建具有类似想法的方法,我很感兴趣:
def myMethod[T](param: T)(implicit oneOf: Either[TypeClass1[T], TypeClass2[T]]) = oneOf match ...
我尝试使用默认参数(我在 akka 中看到过类似的东西):
def myMethod[T](param: T)(implicit t1: TypeClass1[T] = null, t2: TypeClass2[T] = null) =
if (t1 == null) ...
但是,那样我就不能强制 scala 编译器至少找到其中之一。
此外,我已经实现了从 TypeClass1[T]
到 Left[TypeClass1[T], TypeClass2[T]]
以及从 TC2
到 Right
的隐式转换,但是 Scala 编译器会忽略这种转换。
有什么办法可以做到这一点吗?
显而易见的解决方案是创建一个可以使用 TypeClass1
或 TypeClass2
构造的新类型类。新的类型类实现了 myMethod
使用的功能,这对两者都是通用的,并将其映射到 TypeClass1
或 TypeClass2
.
上的适当方法
这是一个例子:
trait TypeClass1[T] {
def showOne = println("Typeclass 1")
}
trait TypeClass2[T] {
def showTwo = println("Typeclass 2")
}
trait UnionTypeClass[T] {
def show
}
object UnionTypeClass {
implicit def t1[T](implicit ev: TypeClass1[T]) = new UnionTypeClass[T] {
def show = ev.showOne
}
implicit def t2[T](implicit ev: TypeClass2[T]) = new UnionTypeClass[T] {
def show = ev.showTwo
}
}
implicit object IntClass extends TypeClass1[Int]
implicit object StringClass extends TypeClass2[String]
def myMethod[T](param: T)(implicit ev: UnionTypeClass[T]) = {
ev.show
}
myMethod(0)
myMethod("hello")
这将打印
Typeclass 1
Typeclass 2
在 Scala 3 中,您可以像这样使用 union type
trait Foo[A]
trait Bar[A]
given foo as Foo[Int] {}
def g[T](using Foo[T] | Bar[T]) = summon
foo[Int] // ok
您可以使用其中一个库中的标准 shapeless.OrElse
或 implicitbox.Priority
https://github.com/milessabin/shapeless
https://github.com/monix/implicitbox
def myMethod[T](param: T)(implicit oneOf: OrElse[TypeClass1[T], TypeClass2[T]]) = ???
// def myMethod[T](param: T)(implicit oneOf: Priority[TypeClass1[T], TypeClass2[T]]) = ???
trait TypeClass1[T]
trait TypeClass2[T]
implicit val tc1: TypeClass1[Int] = ???
implicit val tc2: TypeClass2[String] = ???
myMethod(1) //compiles
myMethod("a") //compiles
类型 类 OrElse
、Priority
与 @Tim 的回答中的 UnionTypeClass
相似,但它们优先考虑 t1
, t2
.
如果我可以创建具有类似想法的方法,我很感兴趣:
def myMethod[T](param: T)(implicit oneOf: Either[TypeClass1[T], TypeClass2[T]]) = oneOf match ...
我尝试使用默认参数(我在 akka 中看到过类似的东西):
def myMethod[T](param: T)(implicit t1: TypeClass1[T] = null, t2: TypeClass2[T] = null) =
if (t1 == null) ...
但是,那样我就不能强制 scala 编译器至少找到其中之一。
此外,我已经实现了从 TypeClass1[T]
到 Left[TypeClass1[T], TypeClass2[T]]
以及从 TC2
到 Right
的隐式转换,但是 Scala 编译器会忽略这种转换。
有什么办法可以做到这一点吗?
显而易见的解决方案是创建一个可以使用 TypeClass1
或 TypeClass2
构造的新类型类。新的类型类实现了 myMethod
使用的功能,这对两者都是通用的,并将其映射到 TypeClass1
或 TypeClass2
.
这是一个例子:
trait TypeClass1[T] {
def showOne = println("Typeclass 1")
}
trait TypeClass2[T] {
def showTwo = println("Typeclass 2")
}
trait UnionTypeClass[T] {
def show
}
object UnionTypeClass {
implicit def t1[T](implicit ev: TypeClass1[T]) = new UnionTypeClass[T] {
def show = ev.showOne
}
implicit def t2[T](implicit ev: TypeClass2[T]) = new UnionTypeClass[T] {
def show = ev.showTwo
}
}
implicit object IntClass extends TypeClass1[Int]
implicit object StringClass extends TypeClass2[String]
def myMethod[T](param: T)(implicit ev: UnionTypeClass[T]) = {
ev.show
}
myMethod(0)
myMethod("hello")
这将打印
Typeclass 1
Typeclass 2
在 Scala 3 中,您可以像这样使用 union type
trait Foo[A]
trait Bar[A]
given foo as Foo[Int] {}
def g[T](using Foo[T] | Bar[T]) = summon
foo[Int] // ok
您可以使用其中一个库中的标准 shapeless.OrElse
或 implicitbox.Priority
https://github.com/milessabin/shapeless
https://github.com/monix/implicitbox
def myMethod[T](param: T)(implicit oneOf: OrElse[TypeClass1[T], TypeClass2[T]]) = ???
// def myMethod[T](param: T)(implicit oneOf: Priority[TypeClass1[T], TypeClass2[T]]) = ???
trait TypeClass1[T]
trait TypeClass2[T]
implicit val tc1: TypeClass1[Int] = ???
implicit val tc2: TypeClass2[String] = ???
myMethod(1) //compiles
myMethod("a") //compiles
类型 类 OrElse
、Priority
与 @Tim 的回答中的 UnionTypeClass
相似,但它们优先考虑 t1
, t2
.