是否可以在Scala中编写一个返回具有不同类型参数的对象的方法?

是否可以在Scala中编写一个返回具有不同类型参数的对象的方法?,scala,type-parameter,Scala,Type Parameter,是否可以在Scala中编写一个方法,返回具有不同类型参数的类型参数化类的对象?大概是这样的: class A[T] def f(switch: Boolean): A = if(switch) new A[Int] else new A[String] 请注意:上面的代码是虚构的,以显示问题的类型;上面的代码在语义上没有意义 上面的代码不会编译,因为返回类型A没有参数化。对“虚构代码”进行一次绝对最小的更改怎么样?如果我们只是在“虚构”返回类型之后添加[\u],代码将编译: class A[

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

class A[T]

def f(switch: Boolean): A = if(switch) new A[Int] else new A[String]
请注意:上面的代码是虚构的,以显示问题的类型;上面的代码在语义上没有意义


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

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

class A[T]
def f(switch: Boolean):A[_] = if(switch) new A[Int] else new A[String]
值得注意的是,
A[\u]
A[Any]
不同<代码>一个[T]不需要定义协变来编译代码。
不幸的是,有关类型的信息丢失了。

您可以这样做,甚至可以借助封装配对的隐式参数使用类型安全性来实现:

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()
类类型映射[+A,B]{
def newListB=List.empty[B]
}
特征逻辑
对象True扩展了逻辑
对象False扩展逻辑
implicit val mapFalseToInt=新类型映射[False.type,Int]
隐式val mapturetoString=新类型映射[True.type,String]
def f[A f(真)
res2:List[String]=List()
scala>f(假)
res3:List[Int]=List()
您必须明确地将布尔值映射到自定义的
True
False

(作为示例,我选择了
List
作为目标类;您可以选择任何内容,甚至只需稍加努力就可以使其成为泛型。)


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

好的,您可以这样做

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

但是这是毫无意义的。类型是编译时信息,而这些信息在这里丢失了。

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

def f(switch: Boolean) = if (switch) Left(new A[Int]) else Right(newA[String])
当然,这会返回一个
或[A[Int],[String]
。您当然不能(目前)声明一个方法,该方法返回一些参数化类型
p
,以及一些类型参数子集(即仅
Int
String

ceylon的语言有联合类型,我知道其目的是在不久的将来将这些类型添加到scala中,在这种情况下,您可以定义一种方法:

def f(switch: Boolean): A[Int|String] = ...

这只对
Any
求值,而对
A
求值。这根本不起作用;您刚刚定义了一个类型参数,它恰好被称为
List
Oops,它是一个返回类型,而不是类型参数。现在修复了!非常有趣;您在实践中使用过这种类型的东西吗(因为它有很多样板文件)?我几乎会争辩说,让这类东西工作所需的机制是一个有用的指针,表明它的核心存在设计缺陷。@oxbow_lakes-事实上,是的,我在实践中确实使用了这一点,尽管只有很少,当我以这种方式保持我的类型正确非常重要的时候。这似乎更容易实现ve 2种方法:
fInt
fString
(至少在这个简化示例中!)@oxbow_lakes-事实上,通常是这样,这就是我很少使用它的原因。事实上,我从来没有以这种形式使用过它;总是有更复杂的事情发生。例如,在一个例子中,我有一套不完全琐碎的类型选择规则,而不是通过三到四个层传播六个不同的函数名作为嵌套的一部分,设置这样的框架更容易。@RexKerr感谢您提供了这个工作示例。通过阅读您的帖子,我有一种感觉,它无意在Scala中做我想做的事情?我看到您的解决方法是可行的,但Scala本身并没有提供直接的方式来完成它?正如Rex的回答所示,如果您使用类型级别boolean,信息不会丢失。感谢您的示例代码。我以前不知道左/右语句。虽然此解决方案是一个解决方案,但所使用的功能对我来说很有趣。是否有其他类/功能,如Earth,可以采取更多的备选方案(编写Earth[Earth[…],Earth[…]看起来有点难看)?