[英]Combining type bounds in Scala
Let's say I have a function such as: 假设我有一个函数,例如:
def foo[T<:U <:V](t:T): Unit
I want to know if there is a way of combining these two in a type W
so that I can have: 我想知道是否有一种将两种类型合并为
W
这样我就可以拥有:
def foo[T<: W](t: T): Unit
The use case for this is: 用例是:
trait FooTrait{
type W
def foo[T<: W](t: T): Unit
}
I might have two different implementations of foo, one of them with a simple W1
type bound whereas the other one is T<:W1 <:W2
I want the more complex one to define a W3
so that I can have: 我可能有两种不同的foo实现,其中一种实现了一个简单的
W1
类型绑定,而另一种实现是T<:W1 <:W2
我想要更复杂的一种来定义W3
这样我就可以拥有:
def foo[T<: W3](t: T): Unit
Similiarly, I want to be able to do these with type classes. 同样,我希望能够使用类型类来实现这些功能。 So if I have:
所以,如果我有:
def bar[T<:U :V](t:T): Unit
I want to have 我希望有
def bar[T:X](t:T): Unit
The use case for this is essentially the same as the earlier case. 此用例与先前的用例基本相同。
is this possible? 这可能吗?
In the first part of your question, the syntax isn't even valid. 在问题的第一部分,语法甚至无效。 If you want to impose multiple upper bounds
U
, V
on some type T
, you have to use with
keyword anyway: 如果你想强加给多个上限
U
, V
对某些类型的T
,你必须使用with
反正关键字:
trait A
trait B
def f[X <: A with B](x: X): Unit = ???
This here doesn't work: 这在这里不起作用:
// def f[X <: A <: B](x: X): Unit = ??? // doesn't compile
To address the second part of your question, I would like to explain why something like with
doesn't work for typeclasses. 为了解决您的问题的第二部分,我想解释一下为什么
with
类的东西对类型类不起作用。
This here does work: 这在这里起作用:
trait Foo[X]
trait Bar[X]
def g[X: Foo : Bar](x: X): Unit = ???
This here doesn't work: 这在这里不起作用:
// def g[X: Foo with Bar](x: X): Unit = ??? // nope
Why? 为什么? Because
因为
def foo[X: Y](x: X): Ret = ???
is actually a shortcut for 实际上是
def foo[X](x: X)(implicit y: Y[X]): Ret = ???
If you would try to somehow amalgamate two different typeclasses Foo
and Bar
, this would result in the following desugared code: 如果您尝试以某种方式合并两个不同的类型类
Foo
和Bar
,则将导致以下简化的代码:
def foo[X](x: X)(implicit superPowerfulThing: (Foo somehowGluedWith Bar)[X]): Ret = ???
But this is obviously not something that you should want. 但这显然不是您应该想要的。 Instead, what you want is:
相反,您想要的是:
def foo[X](x: X)(implicit foo: Foo[X], bar: Bar[X])(x: X): Ret = ???
In this way, the two requirements Foo
and Bar
can be supplied independently, which wouldn't work if you requested some superPowerfulThing
that implements both Foo
and Bar
at once. 这样,可以单独提供
Foo
和Bar
这两个需求,如果您请求一次同时实现Foo
和Bar
superPowerfulThing
,则这是superPowerfulThing
。
Hope that clarifies why something works or doesn't work. 希望能弄清楚为什么某些东西起作用或不起作用。
Andrey Tyukin has correctly point out that with
is probably the answer for your first question and that the second question has no direct solution. Andrey Tyukin正确指出,“
with
可能是您第一个问题的答案,而第二个问题没有直接解决方案。 However if you are OK with indirect solutions, you might work this around by introducing a new type class that will says that the target types belongs to the two original type classes. 但是,如果您可以使用间接解决方案,则可以通过引入一个新的类型类来解决此问题,该类将指出目标类型属于两个原始类型类。 Here is a simple example for imaginary typeclasses
Foo
and Bar
and for a base trait Base
with a specific implementation ChildFooBar
: 这是虚拟类型类
Foo
和Bar
以及具有特定实现ChildFooBar
的基本特征Base
的简单示例:
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
}
Now if SomeClass
is a member of both Foo
and Bar
typeclasses, then 现在,如果
SomeClass
是Foo
和Bar
类型类的成员,则
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}"
}
}
the simple code 简单的代码
println(new ChildFooBar().baz(SomeClass(1, 2.0)))
will compile and work as expected. 将按预期进行编译和工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.