Scala中的类型参数化对象

时间:2015-04-15 15:04:21

标签: scala generics types

有没有办法用通用参数编写对象,如:

object Aaa[T] {
   def f(a: T) = a
}

或者,换句话说,要在实例级别上使用单例,而不是在类型级别上。

我知道我也可以这样做:

object Aaa {
   def f[T](a: T) = a
}

但是如果我有几种限制单一多态类型的方法怎么办:

object Aaa[T] {
   def f1(a: T) = a
   def f2(b: T) = b
}

//somewhere in the code:
val a = Aaa[Int]
import a._

f1(5)
f2(6)
someFunction(a)

P.S。我想要的只是单件工厂,类型参数作为输入(和一个键)。通常它是用Map[TypeTag, Object]实现的(这需要线程安全,顺便说一句) - 在这里寻找更好的解决方案。例如,使用"参数化方法"方法我不能:

trait T1[T] {
   def f1(a: T): T
   def f2(b: T): T
}

object Aaa extends T1 { //won't compile, have to use class
   //some heavy initialization and data here
   (1 to 100500000).map(List.empty[T]) 
   def f1[T](a: T) = a
   def f2[T](b: T) = b
}

可能是某种创建大型结构并需要指定泛型类型的方法。

当然,这个对象可能会传递给另一个函数(或值),因此单个多态类型限制确实有效。

1 个答案:

答案 0 :(得分:2)

是的,可以使用.asInstanceOf

trait AaaImpl[T] {
   this: Aaa.type =>
   def f(a: T) = a
}

object Aaa extends AaaImpl[Nothing] { // lower bound of T should be here
   def apply[T] = this.asInstanceOf[AaaImpl[T]]
}

// Exiting paste mode, now interpreting.

defined trait AaaImpl
defined module Aaa

scala> Aaa[Int].f(5)
res7: Int = 5

scala> Aaa[Double].f(5.0)
res8: Double = 5.0

只要您的对象不执行任何其他类型转换,就可以安全地进行转换。 asInstanceOf只是复制您的类型(使用AaaImpl[Nothing]作为原型),但使用新的类型参数(例如case class的{​​{1}}在值世界中)。

P.S。特质方法也可以在Aaa内部使用,但copy将用于Nothing

P.S.2您还可以实现一些其他特征来将此对象传递给某个外部库:

T

UPDATE1。比身份更冷的东西的例子:

//External
trait SomeAbstractType[T] {
   def f(a: T): T
}

def ff[T](x: SomeAbstractType[T]) = x

//Internal
trait AaaImpl[T] { def f(a: T) = a }

object Aaa extends AaaImpl[Nothing] with SomeAbstractType[Nothing] { // lower bound of T should be here
   def apply[A] = this.asInstanceOf[AaaImpl[A] with SomeAbstractType[A]]
}

// Exiting paste mode, now interpreting.

defined trait SomeAbstractType
ff: [T](x: SomeAbstractType[T])SomeAbstractType[T]
defined trait AaaImpl
defined module Aaa

scala> ff(Aaa[Int])
res11: SomeAbstractType[Int] = Aaa$@6e18a830

scala> ff(Aaa[Double])
res12: SomeAbstractType[Double] = Aaa$@6e18a830 //same instance

scala> ff(Aaa[Int]).f(5) //different behaviour
res15: Int = 5

scala> ff(Aaa[Double]).f(5.0)
res16: Double = 5.0