简体   繁体   English

需要两个隐式参数之一的 Scala 方法

[英]Scala method that needs either one of two implicit parameters

I'm interested if I can create method with similar idea:如果我可以创建具有类似想法的方法,我很感兴趣:

def myMethod[T](param: T)(implicit oneOf: Either[TypeClass1[T], TypeClass2[T]]) = oneOf match ...

I've tried to use default parameters (I've seen somethin similar in akka):我尝试使用默认参数(我在akka中看到过类似的东西):

def myMethod[T](param: T)(implicit t1: TypeClass1[T] = null, t2: TypeClass2[T] = null) = 
  if (t1 == null) ...

However, that way I cannot force scala compiler to find at least one of them.但是,这样我不能强制 scala 编译器至少找到其中一个。

Also, I've implemented implicit conversion from TypeClass1[T] to Left[TypeClass1[T], TypeClass2[T]] and from TC2 to Right , however Scala compiler ignores this conversions.此外,我已经实现了从TypeClass1[T]Left[TypeClass1[T], TypeClass2[T]]和从TC2Right的隐式转换,但是 Scala 编译器会忽略此转换。

Is there any way to do something like this?有没有办法做这样的事情?

The obvious solution is to create a new typeclass that can be constructed using either TypeClass1 or TypeClass2 .显而易见的解决方案是创建一个可以使用TypeClass1TypeClass2构建的新类型类。 The new typeclass implements the functionality used by myMethod that is common to both and maps it to the appropriate methods on TypeClass1 or TypeClass2 .新的 typeclass 实现了myMethod所使用的功能,这两者都是通用的,并将其映射到TypeClass1TypeClass2上的适当方法。


Here is an example:这是一个例子:

  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")

This will print这将打印

Typeclass 1
Typeclass 2

In Scala 3 you might be able to useunion type like so在 Scala 3 中,您可能可以像这样使用联合类型

trait Foo[A]
trait Bar[A]

given foo as Foo[Int] {}

def g[T](using Foo[T] | Bar[T]) = summon
foo[Int] // ok

You can use standard shapeless.OrElse or implicitbox.Priority from one of libraries您可以使用库之一中的标准shapeless.OrElseimplicitbox.Priority

https://github.com/milessabin/shapeless https://github.com/milessabin/shapeless

https://github.com/monix/implicitbox 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

Type classes OrElse , Priority are similar to UnionTypeClass from @Tim 's answer but they prioritize t1 , t2 .类型类OrElsePriority类似于UnionTypeClass答案中的UnionTypeClass ,但它们优先考虑t1t2

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

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