处理多个特定类的通用方法

时间:2019-03-14 00:43:57

标签: scala generics

我需要编写一种可以基于返回类型创建对象的方法。返回类型将是编译时已知的少数类型之一(尽管我很乐意接受运行时解决方案)。

如果重要,则类型是数字类型,而不是原始类型,例如半精度浮点数,并且不会全部继承自Number(或类似数字)。 (我可以创建描述一组特定子类型的基本类型吗?)

我需要类似的东西

object Thing {
   def apply[T](size: Int): Thing[T] = {

     // The call to makeBuffer[T] is inside another generic.
     // I know there are only a limited number types that T can be
     // so I can implement them individually but the compiler does 
     // not know this so it fails to compile
     val buffer = makeBuffer[T](size)

     // more stuff including calling 3rd party generic APIs 
     // that depend on T
   }

   private def [T]makeBuffer(size: Int): Buffer[T] = {
      // What do I put here to build and return the correct Buffer?
   }

   abstract class Buffer[T](size: Int) {
    def doStuff
   }

   // I can implement the small number of concrete classes that I need
   class FloatBuffer(size: Int) extends Buffer[T](size) {
    override def doStuff = // Allocate a buffer with size bytes
   }
}

我不知道如何

  • 向编译器解释我知道T是什么类型。
  • 返回适当的实施方式

我看到的基于TypeTag或使用match的运行时解决方案需要一个输入参数来携带这种情况下我没有的类型信息。

2 个答案:

答案 0 :(得分:0)

首先,Thing是一个对象,因此您申请的返回类型不能为Thing。 另外,Thing不使用通用参数,因此您无法返回Thing[T]

    case class Thing[T](buffer: Thing.Buffer[T])

    object Thing {

        def apply[T](size: Int, clazz: Class[T]): Thing[T] = {

            // The call to makeBuffer[T] is inside another generic.
            // I know there are only a limited number types that T can be
            // so I can implement them individually but the compiler does
            // not know this so it fails to compile
            val result = Thing(makeBuffer(size, clazz))

            // more stuff including calling 3rd party generic APIs
            // that depend on T

            return result
        }

        private def makeBuffer[T](size: Int, clazz: Class[T]): U forSome {type U <: Buffer[T]} = {
            //limited number of classes, so this is probably possible:
            val float = classOf[Float]
            clazz match {
                case `float` => new FloatBuffer(10).asInstanceOf
                //and other types too
            }
        }

        abstract class Buffer[T](size: Int) {
            def doStuff
        }

        // I can implement the small number of concrete classes that I need
        class FloatBuffer(size: Int) extends Buffer[Float](size) {
            override def doStuff = apply(size, classOf[Float])// Allocate a buffer with size bytes
        }
    }

如果您要在缓冲区中存储任何类型的实际实例,并且所有有限类型都共享一个方法,则可以使用结构化类型。不过,您的示例不清楚。

答案 1 :(得分:-2)

我认为这只是要求编译器了解通用类型是什么。我找到了以下运行时解决方案:

import scala.reflect.runtime.universe._

object StupidTypes {

  private abstract class LoadableBuffer(size: Int) {
    type T
    // actual code omitted for brevity
  }

  private class LoadableFloatBuffer(size: Int) extends LoadableBuffer(size) {
    type T = Float
    // actual code omitted for brevity
  }

  private class LoadableDoubleBuffer(size: Int) extends LoadableBuffer(size) {
    type T = Double
    // actual code omitted for brevity
  }

  def main(args: Array[String]): Unit = {
    makeBuffer[Float](1)
    makeBuffer[Double](1)
    makeBuffer[Int](1)
  }

  private def makeBuffer[T: TypeTag](size: Int): LoadableBuffer = {
    typeOf[T] match {
      case t if t =:= typeOf[Float] => new LoadableFloatBuffer(size)
      case t if t =:= typeOf[Double] => new LoadableDoubleBuffer(size)
      case _ => throw new Exception("no can do")
    }
  }
}