我正在尝试大致如下:
/* I assume that we have some types S and T */
sealed trait Container[U]
class SContainer(s: S) extends Container[S]
class TContainer[U <: T](u: U) extends Container[U]
/* this requires something more */
def invoke[U](f: String => U): Container[U]
简单地说,我想要一个Container
类,它可以包含S
类型的内容,也可以包含T
类型的内容。 Container
类明显满足这些属性,因为只有两种可能的方法来构造容器。
但是,现在我想创建一个函数invoke
来包装容器中的值。我的例子中给出的定义显然不起作用,因为我对U
没有限制。
不幸的是,由于类型擦除,我们不能定义两个函数:
def invoke(f: String => S): Container[S]
def invoke[U <: T](f: String => U): Container[U]
因为它们在运行时会有相同的类型。
如何在invoke
上表达这种类型约束?
答案 0 :(得分:2)
我认为以下内容可行。我不知道你的T
和S
是什么,所以我正在尝试使用这些
type T = AnyVal
type S = String
您可以使用视图绑定:
object Container {
implicit def stuffS(s: S): Container[S] = new SContainer(s)
implicit def stuffT[U <: T](u: U): Container[T] = new TContainer(u)
}
sealed trait Container[U]
case class SContainer(s: S) extends Container[S]
case class TContainer[U <: T](u: U) extends Container[T]
然后您的invoke
变为:
def invoke[B, A <% Container[B]](f: String => A): Container[B] = f("hallo")
这些电话有效:
invoke(_.size) // -> Container[T] = TContainer(5)
invoke(_.reverse) // -> Container[S] = SContainer(ollah)
这是不允许的:
invoke(Symbol(_))
修改强>
如果你想要Container[U]
而不是Container[T]
,那就更简单了:
object Container {
implicit def stuffS(s: S): Container[S] = new SContainer(s)
implicit def stuffT[U <: T](u: U): Container[U] = new TContainer(u)
}
sealed trait Container[U]
case class SContainer(s: S) extends Container[S]
case class TContainer[U <: T](u: U) extends Container[U]
def invoke[A <% Container[A]](f: String => A): Container[A] = f("hallo")
invoke(_.size) // Container[Int]
invoke(_.reverse) // Container[String]
invoke(Symbol(_)) // forbidden
答案 1 :(得分:0)
我认为你应该将容器的定义与容器本身可接受的类型的定义分开。
首先让我们说(例如)S是String而T是虚拟类。
class A
class B extends A
type T = A
type S = String
现在,让我们使用类型类模式将T和S的子类定义为容器的可接受内容:
sealed class AcceptableContent[X] private()
object AcceptableContent {
implicit object SAcceptable extends AcceptableContent [S]
implicit def TAcceptable[U <: T] = new AcceptableContent[U]
}
现在可以像这样定义Container类:
class Container[R : AcceptableContent](content: R)
上下文绑定: AcceptableContent
表示只有在范围内存在隐式AcceptableContent [R]时才能接受R,这就是你想要的。
事实上,现在:
scala> new Container("test")
res0: Container[java.lang.String] = Container@1d1fceed
scala> new Container(new A)
res1: Container[A] = Container@631803fb
scala> new Container(new B)
res2: Container[B] = Container@67446579
scala> new Container(true) // Ok, Container accepts String, A, B but not Boolean
<console>:12: error: could not find implicit value for evidence parameter of type AcceptableContent[Boolean]
所以,现在调用变为:
def invoke[N : AcceptableContent](f: String => N) : Container[N] = new Container(f("test"))