1

假设我有一个功能,例如:

def foo[T<:U <:V](t:T): Unit

我想知道是否有一种方法可以将这两者组合成一个类型W,以便我可以拥有:

def foo[T<: W](t: T): Unit

用例是:

trait FooTrait{
   type W
   def foo[T<: W](t: T): Unit
}

我可能有两种不同的 foo 实现,其中一种具有简单的W1类型绑定,而另一种是T<:W1 <:W2我想要更复杂的一种来定义 aW3以便我可以拥有:

def foo[T<: W3](t: T): Unit

同样,我希望能够使用类型类来完成这些。所以如果我有:

def bar[T<:U :V](t:T): Unit

我希望有

def bar[T:X](t:T): Unit

这个用例与前面的案例基本相同。

这可能吗?

4

2 回答 2

3

安德烈·秋金(Andrey Tyukin)正确地指出,这with可能是您第一个问题的答案,而第二个问题没有直接解决方案。但是,如果您对间接解决方案感到满意,您可以通过引入一个新的类型类来解决这个问题,该类将表明目标类型属于两个原始类型类。这是虚构类型类Foo和具有特定实现Bar的基本特征的简单示例:BaseChildFooBar

trait Foo[X] {
  def doFoo(x: X): String
}

trait Bar[X] {
  def doBar(x: X): String
}

trait Base {
  type W[_]

  def baz[T: W](t: T): String
}

class ChildFooBar extends Base {

  import ChildFooBar._

  type W[X] = FooAndBar[X]


  override def baz[T: FooAndBar](t: T): String = {
    val foo = implicitly[Foo[T]]
    val bar = implicitly[Bar[T]]
    foo.doFoo(t) + bar.doBar(t)
  }
}

object ChildFooBar {

  @implicitNotFound("The type should provide both implicit Foo and implicit Bar.")
  case class FooAndBar[X](foo: Foo[X], bar: Bar[X])

  object FooAndBar {
    implicit def fromFooAndBar[X](implicit foo: Foo[X], bar: Bar[X]): FooAndBar[X] = FooAndBar(foo, bar)
  }

  // private is important here to avoid diversion of implicits
  private implicit def toFoo[X](implicit fooAndBar: FooAndBar[X]): Foo[X] = fooAndBar.foo
  private implicit def toBar[X](implicit fooAndBar: FooAndBar[X]): Bar[X] = fooAndBar.bar

}

现在如果SomeClass是两个类型类的成员FooBar那么

case class SomeClass(foo: Int, bar: Double)

object SomeClass {
  implicit val foo: Foo[SomeClass] = new Foo[SomeClass] {
    override def doFoo(x: SomeClass) = s"foo = ${x.foo}"
  }
  implicit val bar: Bar[SomeClass] = new Bar[SomeClass] {
    override def doBar(x: SomeClass) = s"bar = ${x.bar}"
  }
}

简单的代码

println(new ChildFooBar().baz(SomeClass(1, 2.0)))

将按预期编译和工作。

于 2018-01-30T18:44:38.007 回答
3

在您问题的第一部分,语法甚至无效。如果您想在某些类型上施加多个上限U,则无论如何都必须使用关键字:VTwith

trait A
trait B

def f[X <: A with B](x: X): Unit = ???

这在这里不起作用:

// def f[X <: A <: B](x: X): Unit = ??? // doesn't compile

为了解决您问题的第二部分,我想解释一下为什么类似的东西with不适用于类型类。

这在这里确实有效:

trait Foo[X]
trait Bar[X]

def g[X: Foo : Bar](x: X): Unit = ???

这在这里不起作用:

// def g[X: Foo with Bar](x: X): Unit = ??? // nope

为什么?因为

def foo[X: Y](x: X): Ret = ???

实际上是一个捷径

def foo[X](x: X)(implicit y: Y[X]): Ret = ???

如果您尝试以某种方式合并两个不同的类型类FooBar,这将导致以下脱糖代码:

def foo[X](x: X)(implicit superPowerfulThing: (Foo somehowGluedWith Bar)[X]): Ret = ???

但这显然不是您应该想要的。相反,你想要的是:

def foo[X](x: X)(implicit foo: Foo[X], bar: Bar[X])(x: X): Ret = ???

通过这种方式,这两个要求可以独立提供,如果您要求同时实现这两个要求FooBar这将不起作用。superPowerfulThingFooBar

希望能澄清为什么某些东西有效或无效。

于 2018-01-30T14:55:31.383 回答