【问题标题】:generic method to handle a number of specific classes处理许多特定类的通用方法
【发布时间】:2019-03-14 00:43:57
【问题描述】:

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

如果重要的话,类型是数字而不是原始类型,例如半精度浮点数,并且不会全部继承自 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 将是什么类型。
  • 返回适当的实现

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

【问题讨论】:

  • 抱歉新手问题,但这个问题发生了什么?之前有一个答案,好像被删了。我并不完全同意它,但它提供了一个不同的解决方案(我没有想到这可能在其他情况下也有效)。我已经发布了一个答案(对我有用),但已经被否决了两次,没有任何解释!

标签: scala generics


【解决方案1】:

首先Thing是一个对象,所以你的apply返回类型不能是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
        }
    }

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

【讨论】:

    【解决方案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")
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-21
      • 2023-03-17
      • 2019-04-21
      • 1970-01-01
      相关资源
      最近更新 更多