是否可以在Scala中编写一个方法,该方法返回具有不同类型参数的类型参数化类的对象?像这样:
class A[T]
def f(switch: Boolean): A = if(switch) new A[Int] else new A[String]
请注意:上面的代码是虚构的,以显示问题的类型;上面的代码没有语义意义。
上面的代码无法编译,因为返回类型A未参数化。
答案 0 :(得分:6)
你可以,你甚至可以借助封装配对的隐式参数来实现类型安全:
class TypeMapping[+A,B] {
def newListB = List.empty[B]
}
trait Logical
object True extends Logical
object False extends Logical
implicit val mapFalseToInt = new TypeMapping[False.type,Int]
implicit val mapTrueToString = new TypeMapping[True.type,String]
def f[A <: Logical,B](switch: A)(implicit tmap: TypeMapping[A,B]) = tmap.newListB
scala> f(True)
res2: List[String] = List()
scala> f(False)
res3: List[Int] = List()
您必须从布尔值显式映射到自定义True
和False
值。
(我已选择List
作为目标类作为示例;您可以选择任何内容,甚至可以通过更多工作使其成为通用。)
(编辑:正如oxbow_lakes所指出的,如果你需要在同一个代码路径上表示所有可能的返回值,那么单独这样做就不会这样做,因为List[Int]
和{{1}的超类} List[String]
,这没有多大帮助。在这种情况下,您应该使用List[Any]
。我的解决方案是针对单个函数,仅在Either
或{ {1}}上下文,并可以在那里维护类型信息。)
答案 1 :(得分:4)
表达此信息的一种方法是使用Either
;
def f(switch: Boolean) = if (switch) Left(new A[Int]) else Right(newA[String])
这当然会返回Either[A[Int], A[String]]
。你当然不能(目前)声明一个方法,它返回一些参数化类型P
,带有一些类型参数子集(即仅 Int
或 String
)。
语言锡兰有联合类型,我理解的目的是在不久的将来将这些添加到scala,在这种情况下,你可以定义一个方法:< / p>
def f(switch: Boolean): A[Int|String] = ...
答案 2 :(得分:0)
嗯,你可以这样做。
scala> class A {
| type T
| }
defined class A
scala> def f(b: Boolean): A = if(b) new A { type T = Int } else new A { type T = String }
f: (b: Boolean)A
但这毫无意义。类型是编译时信息,这些信息在这里丢失。
答案 3 :(得分:-1)
“虚构代码”的绝对最小变化怎么样?如果我们只是在“虚构”返回类型之后添加[_]
,代码将编译:
class A[T]
def f(switch: Boolean):A[_] = if(switch) new A[Int] else new A[String]
值得注意的是A[_]
与A[Any]
不同。 A[T]
不需要为编译代码定义协变。
不幸的是,有关该类型的信息会丢失。