Scala,泛型类型的重写方法

问题描述 投票:0回答:1

我正在尝试构建DSL,此DSL上的一种方法是无参数的,并使用有界的泛型类型。今天,我必须添加一个“功能”,理想情况下将使用相同的方法名称。但是,因为唯一的参数是通用参数,所以我无法用通常的方法覆盖它。

是否有技巧允许对不同的泛型使用相同的方法?

我的方法如下:

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

而且我想补充:

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

我曾想过在类型上匹配ClassTag的类型,但我需要强大的类型安全性:

  • Query上的[Handler]是不允许的。 ask [State]必须返回QueryBuilder
  • CommandQuery是唯一受支持的类型。 ask的通用类型只能是HandlerState
scala generics overriding dsl
1个回答
0
投票

也许您可以将代码重构为这样的内容?

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
    val 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
}

它按预期工作:

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"
© www.soinside.com 2019 - 2024. All rights reserved.