【问题标题】:Scala method that needs either one of two implicit parameters需要两个隐式参数之一的 Scala 方法
【发布时间】:2020-07-18 11:49:54
【问题描述】:

如果我可以创建具有类似想法的方法,我很感兴趣:

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]] 以及从 TC2Right 的隐式转换,但是 Scala 编译器会忽略这种转换。

有没有办法做这样的事情?

【问题讨论】:

  • 如果有两个重载方法呢?但是,我想这可能会导致歧义,因此您可能还需要混合隐式优先级。

标签: scala implicit


【解决方案1】:

显而易见的解决方案是创建一个可以使用TypeClass1TypeClass2 构造的新类型类。新的类型类实现了 myMethod 使用的功能,这对两者都是通用的,并将其映射到 TypeClass1TypeClass2 上的适当方法。


这是一个例子:

  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

【讨论】:

    【解决方案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
    

    【讨论】:

      【解决方案3】:

      您可以使用其中一个库中的标准 shapeless.OrElseimplicitbox.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
      

      类型类 OrElsePriority 类似于 @Tim 的答案中的 UnionTypeClass,但它们优先考虑 t1t2

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-24
      • 2020-05-23
      • 2021-12-18
      • 1970-01-01
      • 2016-08-02
      • 1970-01-01
      相关资源
      最近更新 更多