2

我想要实现的是一种方法:

  1. 定义异构列表的类型列表
  2. 根据上面的定义,构建一个静态类型的值列表

理想情况下,我想在 IDE 中键入以下表达式:

val record = types.addValue("test").addValue(123).addValue(new java.util.Date())

具有addValue()受 IDE 类型推理引擎约束的参数类型。

以下是第1 点的工作实现:记录字段类型的规范:

case class FieldType[V, T <: FieldType[_, _]](clazz: Class[V], tail: T) {
  def addValue(value: V) = FieldValue(value, tail)
}
case class FieldValue[V, T <: FieldType[_, _]](value: V, tail: T)
object emptyFieldType extends FieldType(classOf[Null], null)

这是由以下组成的记录的示例规范String, Int, Date

val types = FieldType(
  classOf[String], FieldType(
    classOf[Int], FieldType(
      classOf[java.util.Date], emptyFieldType
    )
  )
)

通过使用类型addValue中的方法FieldType,编译器可以识别任何深度的参数类型:

val a = types.addValue("") // here only String allowed
val b = types.tail.addValue(23) // here only Int allowed
val c = types.tail.tail.addValue(new java.util.Date()) // here only Date allowed

但....

我还没有找到一种在FieldValue类型上实现转发方法的方法,以实现一个流畅的接口,就像我的第一个示例一样:

val record = types.addValue("test").addValue(123).addValue(new java.util.Date())

这是给出这个想法的伪代码:

case class FieldValue[V, T <: FieldType[_, _]](value: V, tail: T) {
  def addValue(x: What Here??) = tail.addValue(x) // not compiling!
}

我认为这一定是可能的,因为下一个参数的类型信息通过成员addValue包含在. 但我无法找到一种方法让该信息可用于该方法,让编译器验证参数值的类型,并让 IDE 建议正确的类型。FieldValuetailVaddValue

4

1 回答 1

5

你可能想看看shapeless

这是一个简单的示例,演示如何静态指定异构列表的类型:

type R = String :: Int :: java.util.Date :: HNil

val record: R = "test" :: 123 :: new java.util.Date() :: HNil
// record: R = test :: 123 :: Thu Aug 14 00:21:52 CEST 2014 :: HNil

val record: R = "test" :: "foo" :: new java.util.Date() :: HNil
// error: type mismatch;
found   : shapeless.::[String,shapeless.::[String,shapeless.::[java.util.Date,shapeless.HNil]]]
required: R
  (which expands to)  shapeless.::[String,shapeless.::[Int,shapeless.::[java.util.Date,shapeless.HNil]]]
     val record: R = "test" :: "hola" :: new java.util.Date() :: HNil
                          ^

我不知道这是否已经满足你的需求,但无论如何你一定要检查 shapeless 的所有特性,因为它为这种泛型编程提供了许多便利

于 2014-08-13T22:28:57.153 回答