简体   繁体   English

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

[英]returning different return types in scala

Is there a way to return different return types from a single method in scala? 有没有办法从Scala中的单个方法返回不同的返回类型?

For example, if I have a load() method, I would like to return different data types depending on the object that called this method. 例如,如果我有一个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"
 }

If I understand correctly what you want, F-bounded polymorphism may work for you: 如果我正确理解您的要求,则F界多态性可能会为您工作:

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
}

Then load will return the type of the current object. 然后load将返回当前对象的类型。 Note the result types in those expressions: 注意这些表达式中的结果类型:

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

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

You can use scala's Either : 您可以使用scala的Either

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

As others stated, you can use 正如其他人所述,您可以使用

You can use scala's Either 您可以使用scala的Either

just keep in mind that every method that invokes your method, will need to check which of the types it is returning (using .map or pattern matching). 只需记住,每个调用您方法的方法都需要检查它返回的是哪种类型(使用.map或模式匹配)。 Either is usually used like Either[ErrorType, NormalType] btw, but of course you can use it however you want 通常Either[ErrorType, NormalType]Either[ErrorType, NormalType] btw一样Either[ErrorType, NormalType] ,但是当然您可以根据需要使用它

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

and of course, scalaz also provides an alternative: http://appliedscala.com/blog/2016/scalaz-disjunctions/ 当然,scalaz还提供了另一种选择: http ://appliedscala.com/blog/2016/scalaz-disjunctions/

As a last resort, don't you can define your own "Either" 万不得已,您不能定义自己的“两者皆有”

If your requirement is as simple as returning some instance of the type of context instance... ie this then you can just do this, 如果您的要求是返回类型的上下文实例...即一些实例作为简单的this那么你可以做到这一点,

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

And if inheritence is involved, 如果涉及继承,

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

But if you want more generality then you may want to read the following and apply it there, 但是,如果您想要更多的通用性,那么您可能需要阅读以下内容并将其应用于此处,

The easiest way will be to take inspiration from the magnet pattern which was heavily used in Spray. 最简单的方法是从在Spray中大量使用的magnet pattern中汲取灵感。

We can leverage the inspiration to build our custom solution, remember it is neither pure magnet pattern nor is path dependent type approach. 我们可以利用灵感来构建我们的自定义解决方案,请记住,它既不是pure magnet pattern也不是path dependent type方法。 Its a hacky cocktail of both. 两者兼有。

So... lets say you want your def process to be able to support input parameters of type Int and String and finally return the respective result. 所以...可以说,您希望def process能够支持IntString类型的输入参数,并最终返回各自的结果。

You will need to define implicit magnets for these types, 您需要为这些类型定义隐式磁体,

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]

what about factory method and just defining a trait loadable eg: 关于工厂方法,只是定义一个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)
  }
}

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

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