2017-01-09 182 views
0

有没有办法从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" 
} 
+2

尝试的[要么](HTTP:// www.scala-lang.org/api/2.12.0/scala/util/Either.html):'Type1,Type2]' –

+1

type1和type2之间是否有任何关系? – mfirry

+0

你可以阅读'磁铁图案'或'路径依赖类型' –

回答

1

您可以使用Scala的Either

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

感谢您的快速响应。但是我发现用户必须左右调用来获取正确的对象,有没有办法避免它?例如:只需调用object1.load(“path”)应该直接返回类型为“object1”的对象而不是object1.load(“path”)。right.get – Garipaso

+0

scalaz有一个叫做disjuction的构造,它是“右偏“,例如它有一个映射方法,如果它被设置,它将在正确的值上运行。但是没有办法保持类型安全,并且返回2个可能值中的1个,而没有某种需要以某种方式索引的“容器”...... –

0

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

您可以使用Scala的Either

只要记住,每一个方法调用你的方法,将需要检查它返回哪种类型(使用.map或模式匹配)。无论是平时使用像Either[ErrorType, NormalType]顺便说一句,当然你可以使用它,但是你想

斯卡拉猫库有其他的选择:http://eed3si9n.com/herding-cats/Xor.html

当然,scalaz还提供了一种替代方案:http://appliedscala.com/blog/2016/scalaz-disjunctions/

由于不得已,难道你可以定义自己的“或者”

3

如果我理解正确的话,你想要什么,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 
} 

Then load将返回当前对象的类型。请注意,结果类型的表达式:

new Type1().load(path) 
scala> res2: Type1 = [email protected] 

new Type2().load(path) 
scala> res3: Type2 = [email protected] 
+0

如果您在特定类中重写,则使用F限制多态的意义是什么? ?是不是你的例子等于一个过于复杂的工厂方法? – Raffaello

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