简体   繁体   English

Scala,覆盖泛型类型的方法

[英]Scala, override method on generic type

I am trying to build a DSL , one of the method on this DSL is parameterless and use a bounded generic type.我正在尝试构建DSL ,此 DSL 上的方法之一是无参数的,并使用有界泛型类型。 Today I have to add a "feature" that will ideally use the same method name.今天我必须添加一个“功能”,理想情况下将使用相同的方法名称。 However, because the only parameter is the generic one, I cannot override it with the usual way.但是,因为唯一的参数是通用参数,所以我不能用通常的方式覆盖它。

Is there a trick to allow the use of the same method for different generic types ?是否有允许对不同泛型类型使用相同方法的技巧?

My method looks like:我的方法看起来像:

def ask[H <: Handler] = {
  new CommandBuilder[H]
}
class CommandBuilder[H <: Handler] {
  def toExecute[C <: H#C](command: C) = {
    //...
  }
} 

And I would like to add:我想补充一点:

def ask[S <: State] = {
  new QueryBuilder[S]
}
class QueryBuilder[S <: State] {
  def toExecute[Q <: S#Q](query: Q) = {
    //...
  }
} 

I was thinking to pattern match a ClassTag on the type but I need strong type safety:我想在类型上模式匹配ClassTag但我需要强类型安全:

  • Query on a Handler , is not allowed.不允许Query Handler ask[State] must return QueryBuilder ask[State] 必须返回 QueryBuilder
  • Command and Query are the only supported types. CommandQuery是唯一支持的类型。 The generic type of ask can only be a Handler or a State . ask的通用类型只能是HandlerState

Maybe you could refactor your code to something like this?也许你可以将你的代码重构为这样的东西?

sealed trait FooBar

sealed trait Foo extends FooBar {
  def process(i: Int): Int
}

object Foo {
  implicit final case object FooImpl extends Foo {
    override def process(i: Int): Int = i + 1
  }
}

sealed trait Bar extends FooBar {
  def process(s: String): String
}

object Bar {
  implicit final case object BarImpl extends Bar {
    override def process(s: String): String = s.toUpperCase
  }
}

object Test {
  trait FooBarPartiallyApplied[FB <: FooBar] {
    type Out
    def out: Out
  }

  object FooBarPartiallyApplied {
    type Aux[FB <: FooBar, _Out] = FooBarPartiallyApplied[FB] { type Out = _Out }

    implicit final def FooPartiallyAppliedBuilder[F <: Foo]: Aux[F, FooPartiallyApplied[F]] =
      new FooBarPartiallyApplied[F] {
        override final type Out = FooPartiallyApplied[F]

        override final val out: FooPartiallyApplied[F] =
          new FooPartiallyApplied[F](dummy = true)
      }

    implicit final def BarPartiallyAppliedBuilder[B <: Bar]: Aux[B, BarPartiallyApplied[B]] =
      new FooBarPartiallyApplied[B] {
        override final type Out = BarPartiallyApplied[B]

        override final val out: BarPartiallyApplied[B] =
          new BarPartiallyApplied[B](dummy = true)
      }

    final class FooPartiallyApplied[F <: Foo](private val dummy: Boolean) extends AnyVal {
      def toExecute(i: Int)(implicit foo: F): Int = foo.process(i)
    }

    final class BarPartiallyApplied[B <: Bar](private val dummy: Boolean) extends AnyVal {
      def toExecute(s: String)(implicit bar: B): String = bar.process(s)
    }
  }

  def ask[FB <: FooBar](implicit pa: FooBarPartiallyApplied[FB]): pa.Out =
    pa.out
}

It works as expected:它按预期工作:

Test.ask[Foo.FooImpl.type].toExecute(10)
// res: Int = 11

Test.ask[Foo.FooImpl.type].toExecute("blah")
// Type error.

Test.ask[Bar.BarImpl.type].toExecute(10)
// Type error.

Test.ask[Bar.BarImpl.type].toExecute("blah")
// res: String = "BLAH"

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

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