简体   繁体   English

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

[英]Is it possible to write a method in Scala returning objects with different type parameter?

Is it possible to write a method in Scala which returns an object of a type-parameterized class with different type paramter ? 是否可以在Scala中编写一个方法,该方法返回具有不同类型参数的类型参数化类的对象? Something like this: 像这样的东西:

class A[T]

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

Please note: The Code above is fictional to show the type of problem; 请注意:上面的代码是虚构的,以显示问题的类型; The code above does not make semantically sense. 上面的代码没有语义意义。

The code above will not compile because return type A is not parameterized. 上面的代码将无法编译,因为返回类型A未参数化。

You can, and you can even do it with type-safety with the aid of implicit arguments that encapsulate the pairings: 你可以,你甚至可以借助封装配对的隐式参数来实现类型安全:

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

You do have to explicitly map from boolean values to the custom True and False values. 您必须显式地从布尔值映射到自定义的TrueFalse值。

(I have chosen List as the target class just as an example; you could pick anything or even make it generic with a little more work.) (我已经选择List作为目标类作为一个例子;你可以选择任何东西,甚至可以通过更多的工作使它成为通用的。)

(Edit: as oxbow_lakes points out, if you need all possible return values to be represented on the same code path, then this alone won't do it, because the superclass of List[Int] and List[String] is List[Any] , which isn't much help. In that case, you should use an Either . My solution is for a single function that will be used only in the True or False contexts, and can maintain the type information there.) (编辑:正如oxbow_lakes所指出的,如果你需要在同一代码路径上表示所有可能的返回值,那么单独就不会这样做,因为List[Int]List[String]的超类是List[Any] ,这是没有太大的帮助。在这种情况下,你应该使用的Either 。我的解决办法是将在只能用单一的功能TrueFalse的上下文,并在那里保持类型的信息。)

One way of expressing this would be by using Either ; 表达这一点的一种方法是使用Either ;

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

This of course returns an Either[A[Int], A[String]] . 这当然会返回一个Either[A[Int], A[String]] You certainly cannot (at the moment) declare a method which returns some parameterized type P , with some subset of type parameters (ie only Int or String ). 你当然不能(目前)声明一个方法,它返回一些参数化类型P ,带有一些类型参数的子集(即只有 Int String )。

The language ceylon has union types and I understand the intention is to add these to scala in the near future, in which case, you could define a method: 语言锡兰有联合类型,我理解的意图是在不久的将来将这些添加到scala,在这种情况下,您可以定义一个方法:

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

Well, you could do something like that. 好吧,你可以做那样的事情。

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

But this is pointless. 但这毫无意义。 Types are a compile time information, and that information is getting lost here. 类型是编译时信息,这些信息在这里丢失。

How about an absolutely minimal change to the "fictional code"? 对“虚构代码”进行绝对微小的改动怎么样? If we just add [_] after the "fictional" return type, the code will compile: 如果我们只是在“虚构”返回类型之后添加[_] ,代码将编译:

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

It is worth noting that A[_] is not the same as A[Any] . 值得注意的是A[_]A[Any] A[T] does not need to be defined covariant for the code to compile. 对于要编译的代码,不需要为A[T]定义协变。 Unfortunately, information about the type gets lost. 不幸的是,有关该类型的信息会丢失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM