3

是否可以在 Scala 中编写一个方法,该方法返回具有不同类型参数的类型参数化类的对象?像这样的东西:

class A[T]

def f(switch: Boolean): A = if(switch) new A[Int] else new A[String]

请注意:上面的代码是虚构的,以显示问题的类型;上面的代码在语义上没有意义。

上面的代码不会编译,因为返回类型 A 没有参数化。

4

4 回答 4

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()

您确实必须从布尔值显式映射到自定义TrueFalse值。

(我选择List作为目标类只是一个例子;你可以选择任何东西,甚至可以通过更多的工作使其通用。)

(编辑:正如 oxbow_lakes 指出的那样,如果您需要在同一代码路径上表示所有可能的返回值,那么仅此一项是行不通的,因为 and 的超类List[Int]is List[String]List[Any]这没有多大帮助。在这种情况下,您应该使用. 我的解决方案是针对仅在or上下文Either中使用的单个函数,并且可以在那里维护类型信息。)TrueFalse

于 2012-06-25T15:43:02.607 回答
4

表达这一点的一种方法是使用Either;

def f(switch: Boolean) = if (switch) Left(new A[Int]) else Right(newA[String])

这当然会返回一个Either[A[Int], A[String]]. 您当然不能(目前)声明一个返回一些参数化类型的方法P,以及一些类型参数的子集(即只有 Int or String)。

锡兰语言具有联合类型,我理解其意图是在不久的将来将这些添加到 scala 中,在这种情况下,您可以定义一个方法:

def f(switch: Boolean): A[Int|String] = ...
于 2012-06-25T15:43:40.923 回答
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

但这是没有意义的。类型是编译时信息,而该信息在这里丢失了。

于 2012-06-25T15:43:35.273 回答
-1

对“虚构代码”进行绝对最小的更改怎么样?如果我们只是[_]在“虚构”返回类型之后添加,代码将编译:

class A[T]
def f(switch: Boolean):A[_] = if(switch) new A[Int] else new A[String]

值得注意的A[_]是不一样A[Any]A[T]不需要为编译代码定义协变。不幸的是,有关类型的信息会丢失。

于 2012-06-25T15:37:17.247 回答