2017-01-09 183 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) 
    } 
}