Scala 中的类型参数化对象
type-parametrized object in Scala
有没有办法用泛型参数编写对象,像这样:
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]
实现的(顺便说一句,这需要线程安全)——在这里寻找更好的解决方案。例如,使用 "parametrize method" 方法我不能:
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
}
可能是某种方法创建了一个大结构并且需要指定通用类型。
当然这个对象可能会被传递给另一个函数(或值),所以单一多态类型限制确实有效。
是的,可以使用 .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
的 copy
在价值观世界中所做的那样)。
P.S。 Trait 的方法也可以在 Aaa 内部使用,但是 Nothing
将用于 T
P.S.2 您还可以实现一些其他特征以将此对象传递给某个外部库:
//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
更新1。比身份更酷的例子:
scala> trait AaaImpl[T] {
def list(a: T) = List(a)
def empty = List[T]()
def square(a:T)(implicit n:Numeric[T]) = n.times(a, a)
}
defined trait AaaImpl
scala> object Aaa extends AaaImpl[Nothing]{ // lower bound of T should be here
def apply[A] = this.asInstanceOf[AaaImpl[A]]
}
defined module Aaa
scala> Aaa[Int].list(5)
res21: List[Int] = List(5)
scala> Aaa[Int].empty
res22: List[Int] = List()
scala> Aaa[Int].square(5)
res23: Int = 25
scala> Aaa[List[Int]].square(5)
<console>:11: error: type mismatch;
found : Int(5)
required: List[Int]
Aaa[List[Int]].square(5)
^
有没有办法用泛型参数编写对象,像这样:
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]
实现的(顺便说一句,这需要线程安全)——在这里寻找更好的解决方案。例如,使用 "parametrize method" 方法我不能:
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
}
可能是某种方法创建了一个大结构并且需要指定通用类型。
当然这个对象可能会被传递给另一个函数(或值),所以单一多态类型限制确实有效。
是的,可以使用 .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
的 copy
在价值观世界中所做的那样)。
P.S。 Trait 的方法也可以在 Aaa 内部使用,但是 Nothing
将用于 T
P.S.2 您还可以实现一些其他特征以将此对象传递给某个外部库:
//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
更新1。比身份更酷的例子:
scala> trait AaaImpl[T] {
def list(a: T) = List(a)
def empty = List[T]()
def square(a:T)(implicit n:Numeric[T]) = n.times(a, a)
}
defined trait AaaImpl
scala> object Aaa extends AaaImpl[Nothing]{ // lower bound of T should be here
def apply[A] = this.asInstanceOf[AaaImpl[A]]
}
defined module Aaa
scala> Aaa[Int].list(5)
res21: List[Int] = List(5)
scala> Aaa[Int].empty
res22: List[Int] = List()
scala> Aaa[Int].square(5)
res23: Int = 25
scala> Aaa[List[Int]].square(5)
<console>:11: error: type mismatch;
found : Int(5)
required: List[Int]
Aaa[List[Int]].square(5)
^