【发布时间】:2016-04-20 14:12:00
【问题描述】:
我创建了一个类型层次结构S_3 <: S_2 <: S_1 <: S_0 <: Selector,我想用它从数据结构中选择一个字段,同时保证用户不会要求一个不存在的字段。
例如如果_1, _2 and _3 是S_1, S_2 and S_3 类型的构造函数,那么我的意图如下:
val x : (Int, String) = ..
x(_0) : TypeError
x(_1) : Int
x(_2) : String
x(_3) : TypeError!
我的第一种方法是将类型限制如下:
implicit class Bla2[+A,+B](val x : (A,B)) {
def apply[N >: S_2 <: S_1](i : N) : Any = {
i match {
case 1 => x._1
case 2 => x._2
}
}
其中关键信息是:N >: S_2 <: S_1。我希望 scala 会从提供的值x: N 推断出该类型是否允许。然而,这并没有发生,确切地说。
如果我编译以下内容(其中 _3 是 S_3 的构造函数):
val x : (Int, String) = (1, "hello")
x(_3)
它会愉快地编译。
对于 _0 它工作正常。
我可以看到这样做的原因。因为 S_3 <: s_2 scala>
对于 S_0,它可以工作。因为 S_0 >: S_2 <: s_1 s_0>
我需要一种方法来强制 scala 不泛化类型并使其尽可能具体。我怎样才能做到这一点?
我知道可以通过使用类型编码的 Naturals 或其他结构更丰富的类型来实现,但我希望代码尽可能简单。我只需要一个订单。
完整代码如下(整个元组只是为了测试目的):
object Main extends App {
sealed trait Selector {
def unapply() : Int
}
sealed class S_0 extends Selector {
def unapply() : Int = 0
}
sealed class S_1 extends S_0 {
override def unapply() : Int = 1
}
sealed class S_2 extends S_1 {
override def unapply() : Int = 2
}
sealed class S_3 extends S_2 {
override def unapply() : Int = 3
}
def _0 = new S_0
def _1 = new S_1
def _2 = new S_2
def _3 = new S_3
implicit class Bla2[+A,+B](val x : (A,B)) {
def apply[N >: S_2 <: S_1](i : N) : Any = {
i match {
case 1 => x._1
case 2 => x._2
}
}
}
println("hello world")
val b = (1,2)
b[S_1](_1)
b[S_2](_2)
// this won't compile
// b[S_3](_3)
// but this will
b(_3)
}
编辑:问题在于类型的推断。如果类型被显式指定为:b[S_3](_3),它将不会编译。
【问题讨论】:
-
也许,使用 shapeless 更容易
Nat类型:stackoverflow.com/questions/28287612/… -
@dk14 确实有效,但我很好奇是否有办法强制类型推断更具体。如果手动指定类型
b[S_3](_3),编译器会正确拒绝该语句。有时你不想仅仅为了一个特性而引入整个库。