在scala中返回不同的返回类型

时间:2017-01-09 18:47:19

标签: scala

有没有办法从scala中的单个方法返回不同的返回类型?

例如,如果我有一个load()方法,我想根据调用此方法的对象返回不同的数据类型。

def load(path: String):<return type> 
{
    // if this instance is of type "type1", do some processing on this object, 
    // and return object of type "type1"

    // else if this instance is of type "type2", do some processing on this object,
    // and return object of type return "type2"
 }

5 个答案:

答案 0 :(得分:4)

如果我理解你想要的是什么,F-bounded polymorphism可能适合你:

trait Base[T <: Base[T]] {
  def load(path: String): T
}

class Type1 extends Base[Type1] {
  override def load(path: String): Type1 = new Type1 // provisional implementation
}

class Type2 extends Base[Type2] {
  override def load(path: String): Type2 = new Type2
}

然后load将返回当前对象的类型。请注意这些表达式中的结果类型:

new Type1().load(path)
scala> res2: Type1 = Type1@744f0e0b

new Type2().load(path)
scala> res3: Type2 = Type2@77988c45

答案 1 :(得分:1)

您可以使用scala&#39; Either

def load(path : String) : Either[Type1, Type2] = {
  this match {
    case t1 : Type1 => Left(someProcessing(t1))
    case t2 : Type2 => Right(someOtherProcessing(t2))
  }
}

答案 2 :(得分:0)

正如其他人所说,你可以使用

您可以使用scala的Either

请记住,调用方法的每个方法都需要检查它返回的类型(使用.map或模式匹配)。通常使用Either[ErrorType, NormalType] btw,但当然你可以随意使用

scala cats library还有其他选择:http://eed3si9n.com/herding-cats/Xor.html

当然,scalaz还提供了另一种选择:http://appliedscala.com/blog/2016/scalaz-disjunctions/

作为最后的手段,你不能定义自己的“Either”

答案 3 :(得分:0)

如果您的要求就像返回上下文实例类型的某个实例一样简单...即this那么您可以这样做,

class A() {
  def omg(s: String): this.type = new A()
}

如果涉及遗产,

trait A {
  type omgType

  def omg(s: String): omgType
}

class B() extends A {
  override type omgType = this.type

  override def omg(s: String): omgType = new B()
}

class C() extends A {
  override type omgType = this.type

  override def omg(s: String): omgType = new C()
}

但是如果你想要更多的一般性,那么你可能想要阅读以下内容并将其应用于那里,

最简单的方法是从喷雾中大量使用的magnet pattern中获取灵感。

我们可以利用灵感来构建我们的自定义解决方案,记住它既不是pure magnet pattern也不是path dependent type方法。它是两者的黑巧克力。

所以...让我们假设您希望def process能够支持IntString类型的输入参数,最后返回相应的结果。

您需要为这些类型定义隐式磁铁,

trait ProcessMagnet {
  type Input
  type Result
  def input: Input
  def process: Result
}

object ProcessMagnetProvider {
  implicit def stringToStringProcessMagnet(string: String): ProcessMagnet = new ProcessMagnet {
    override type Input = String
    override type Result = String

    override def input: Input = string
    // define this for your doing...
    override def process: Result = input + "_omg"
  }
  //... add for all your inputs
  implicit def intToIntProcessMagnet(int: Int): ProcessMagnet = new ProcessMagnet {
    override type Input = Int
    override type Result = Int

    override def input: Input = int
    // define this for your doing...
    override def process: Result = input + 1
  }
}

def process[T](t: T)(implicit pmConverter: T => ProcessMagnet): ProcessMagnet = pmConverter(t)

// now just import our implicit magnets...
import ProcessMagnetProvider._

val intResult: Int = process(5).process.asInstanceOf[Int]

val stringResult: String = process("omg").process.asInstanceOf[String]

答案 4 :(得分:0)

工厂方法怎么样,只是定义特征loadable,例如:

trait Loadable {
  def load(path: String): Loadable
}

class Type1 extends Loadable {
    def load(path: String): Type1 = this
}

class Type2 extends Loadable {
  def load(path: String): Type2 = this
}
object Main {
  def test(): Loadable = {
    new Type1().load("path")
  }

  def main(args: Array[String]): Unit = { 
    println(test().getClass)
  }
}